public PresentedParameter Present(IParameterDescriptor param, Action updateCallback)
        {
            var pathType       = PathTypeProperty.Get(param.Metadata);
            var checkExistence = CheckExistenceProperty.Get(param.Metadata);
            var container      = new Grid();
            var textBox        = new TextBox {
                MaxLength = 256
            };

            textBox.TextChanged += (sender, args) => updateCallback();
            container.Children.Add(textBox);

            Button button = null;

            if (ShowSelectorProperty.Get(param.Metadata))
            {
                button = new Button {
                    Content = "...", HorizontalAlignment = HorizontalAlignment.Right, Width = 25
                };
                textBox.Margin = new Thickness {
                    Right = ViewConstants.MinorSpacing + button.Width
                };
                button.Click += (sender, args) =>
                {
                    switch (pathType)
                    {
                    case PathType.File:
                        var openFileDialog = new OpenFileDialog
                        {
                            Title           = $"Select File: {param.Name}",
                            Multiselect     = false,
                            CheckFileExists = checkExistence,
                            Filter          = FilterProperty.Get(param.Metadata),
                        };
                        if (!textBox.Text.IsBlank())
                        {
                            openFileDialog.InitialDirectory = new FileInfo(textBox.Text).Directory?.FullName ?? "";
                        }
                        if ((bool)openFileDialog.ShowDialog(Window.GetWindow(button)))
                        {
                            textBox.Text = openFileDialog.FileName;
                        }
                        break;

                    case PathType.Directory:
                        using (var dialog = new System.Windows.Forms.FolderBrowserDialog())
                        {
                            if (!textBox.Text.IsBlank())
                            {
                                dialog.SelectedPath = textBox.Text;
                            }
                            var result = dialog.ShowDialog();
                            if (result == System.Windows.Forms.DialogResult.OK)
                            {
                                textBox.Text = dialog.SelectedPath;
                            }
                        }

                        break;
                    }
                };
                container.Children.Add(button);
            }
            void Setter(object file) => textBox.Text = ((Path)file)?.Value ?? "";
            object Getter() => new Path(textBox.Text);

            bool Validate(object value)
            {
                if (!(value is Path file))
                {
                    return(false);
                }
                if (checkExistence)
                {
                    switch (pathType)
                    {
                    case PathType.File:
                        if (!File.Exists(file.Value))
                        {
                            return(false);
                        }
                        break;

                    case PathType.Directory:
                        if (!Directory.Exists(file.Value))
                        {
                            return(false);
                        }
                        break;
                    }
                }
                return(param.IsValid(value));
            }

            void Updater(ParameterStateType state, bool value)
            {
                switch (state)
                {
                case ParameterStateType.Enabled:
                    textBox.IsEnabled = value;
                    if (button != null)
                    {
                        button.IsEnabled = value;
                    }
                    break;

                case ParameterStateType.Valid:
                    textBox.Background = value ? Brushes.Transparent : new SolidColorBrush(ViewConstants.InvalidColor);
                    break;
                }
            }

            return(new PresentedParameter(param, container, new PresentedParameter.ParamDelegates(Getter, Setter, Validate, Updater)));
        }
        public PresentedParameter Present(IParameterDescriptor param, Action updateCallback)
        {
            var container          = new Grid();
            var checkFileExistence = CheckFileExistenceProperty.Get(param.Metadata);

            var textBox = new TextBox {
                MaxLength = 256
            };

            textBox.TextChanged += (sender, args) => updateCallback();
            container.Children.Add(textBox);

            var supportedSchemes = new HashSet <string>((SupportedSchemesProperty.GetOrDefault(param.Metadata) ?? EmptyArray <string> .Instance).Select(scheme => scheme.ToLowerInvariant()));

            Button button = null;

            if ((!supportedSchemes.Any() || supportedSchemes.Contains("file")) && ShowFileSelectorProperty.GetOrDefault(param.Metadata))
            {
                button = new Button {
                    Content = "...", HorizontalAlignment = HorizontalAlignment.Right, Width = 25
                };
                textBox.Margin = new Thickness {
                    Right = ViewConstants.MinorSpacing + button.Width
                };
                button.Click += (sender, args) =>
                {
                    var dialog = new OpenFileDialog
                    {
                        Title           = $"Select File: {param.Name}",
                        Multiselect     = false,
                        CheckFileExists = CheckFileExistenceProperty.Get(param.Metadata),
                        Filter          = FileFilterProperty.Get(param.Metadata),
                    };
                    if (!textBox.Text.IsBlank())
                    {
                        Uri uri = null;
                        try
                        {
                            uri = new Uri(textBox.Text, UriKind.RelativeOrAbsolute);
                        }
                        catch (Exception)
                        {
                            /* ignored */
                        }

                        if (uri?.IsFile ?? false)
                        {
                            var localPath = uri.LocalPath;
                            dialog.InitialDirectory = new FileInfo(localPath).Directory?.FullName ?? "";
                        }
                    }

                    if ((bool)dialog.ShowDialog(Window.GetWindow(button)))
                    {
                        textBox.Text = "file:\\" + dialog.FileName;
                    }
                };
                container.Children.Add(button);
            }

            void Setter(object uri) => textBox.Text = uri?.ToString() ?? "";
            object Getter() => new Uri(textBox.Text);

            bool Validator(object val)
            {
                if (val is Uri uri)
                {
                    if (!supportedSchemes.Any() && !supportedSchemes.Contains(uri.Scheme.ToLowerInvariant()))
                    {
                        return(false);
                    }
                    if (string.Equals(uri.Scheme, "file", StringComparison.OrdinalIgnoreCase) && checkFileExistence && !File.Exists(uri.LocalPath))
                    {
                        return(false);
                    }
                }
                return(param.IsValid(val));
            }

            void Updater(ParameterStateType state, bool value)
            {
                switch (state)
                {
                case ParameterStateType.Enabled:
                    textBox.IsEnabled = value;
                    if (button != null)
                    {
                        button.IsEnabled = value;
                    }
                    break;

                case ParameterStateType.Valid:
                    textBox.Background = value ? Brushes.Transparent : new SolidColorBrush(ViewConstants.InvalidColor);
                    break;
                }
            }

            return(new PresentedParameter(param, container, new PresentedParameter.ParamDelegates(Getter, Setter, Validator, Updater)));
        }