internal static object StringWithTextBox <TOut>(object o, PropertyInfo p, Func <object> gv, Action <object> sv, EditorRule.ParseFunc <string, TOut, bool> parseFunc, bool supportNullable = true, bool supportEnumerable = true, bool liveUpdate = true) => StringWithTextBox(o, p, gv, sv, (string input, out object output) => { var ret = parseFunc(input, out var outT); output = outT; return(ret); }, supportNullable, supportEnumerable, liveUpdate);
public static object StringWithTextBox(object o, PropertyInfo p, Func <object> gv, Action <object> sv, EditorRule.ParseFunc <string, object, bool> parseFunc, bool supportNullable = true, bool supportEnumerable = true, bool liveUpdate = true) { var type = p.PropertyType; var isEnumerable = supportEnumerable && type.GetArrayLikeElementType() != null; // handle string which is IEnumerable<char> if (type == typeof(string) && type.GetArrayLikeElementType() == typeof(char)) { isEnumerable = false; } string GetStringRepresentationForValue() { var v = gv(); var desc = v == null ? NullString : (isEnumerable ? JsonConvert.SerializeObject(v) : $"{v}"); // hyperlinq doesn't like empty strings if (desc == String.Empty) { desc = EmptyString; } return(desc); } bool TryGetParsedValue(string str, out object @out) { var canConvert = parseFunc(str, out var output); if (isEnumerable) { try { var val = JsonConvert.DeserializeObject(str, type); @out = val; return(true); } catch { @out = null; return(false); // can't deserialise } } if (canConvert) { @out = output; return(true); } if (supportNullable && (str == String.Empty)) { @out = null; return(true); } @out = null; return(false); // can't convert } var updateButton = new Button("update") { Visible = false }; Action <ITextControl> onText = t => { var canParse = TryGetParsedValue(t.Text, out var newValue); if (liveUpdate && canParse) { sv(newValue); } else { updateButton.Visible = canParse; } }; var initialText = GetStringRepresentationForValue() ?? ""; var s = !isEnumerable ? (ITextControl) new TextBox(initialText, WidthForTextBox(o, p), onText) { IsMultithreaded = true } : (ITextControl) new TextArea(initialText, 40, onText) { IsMultithreaded = true }; updateButton.Click += (sender, e) => { if (!TryGetParsedValue(s.Text, out var newValue)) { return; } sv(newValue); updateButton.Visible = false; }; var dc = new DumpContainer { Style = "text-align: center; vertical-align: middle;", Content = Util.HorizontalRun(true, s, updateButton) }; return(dc); }