开发者

Creating a form with additional dynamic fields specified by customer, options?

开发者 https://www.devze.com 2023-02-03 05:26 出处:网络
We have a desktop app which basically models a job for a specific sector (Transport for example) with things like job date, references, driver allocation etc which is then sent to/from PDAs for status

We have a desktop app which basically models a job for a specific sector (Transport for example) with things like job date, references, driver allocation etc which is then sent to/from PDAs for status updates.

Although it's mainly off the shelf, we usually end up having to do bespoke parts to suit the company, which about 90% of the time it only additional data fields that don't really require any logic, only storing / retrieval.

I've been looking around for a basic drag and drop library to turn a form into an editable mode that I could save position, component type, default value and populate at runtime in non-edit mode but haven't really been able to find one.

Is the best way to just roll my own or am I missing a library that will get me 60% of the way there? WPF or Winf开发者_如何学Corms help would be appreciated (we're using Winforms but moving to WPF).

Cheers,

Thomas


I'd suggest you just write your own. In the most basic case of a form with a vertical list of labelled controls my intuitive approach would be to have a data object that consists of a ordered list of string-object-pairs (maybe make it a triple with a validation rule too), when the form should be loaded each object's type is checked and if it is a string you create a textbox, if it's a bool you create a checkbox etc. You can also have input-validation if you have int and doubles for example. The other direction shouldn't be too hard either.
I've written semi-dynamic generic edit dialogues before like the following (WPF): Window Content XAML:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition />
    </Grid.RowDefinitions>
    <StackPanel Name="StackPanelInput" Grid.Row="0" Orientation="Vertical" VerticalAlignment="Top" Margin="5"/>
    <StackPanel Grid.Row="1" Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="5">
        <Button Name="ButtonOK" HorizontalAlignment="Right" Width="100" Margin="5" Click="ButtonOK_Click" IsDefault="True">OK</Button>
        <Button Name="ButtonCancel" HorizontalAlignment="Right" Width="100" Margin="5" Click="ButtonCancel_Click" IsCancel="True">Cancel</Button>
    </StackPanel>
</Grid>

Code-behind:

public partial class EditDialog : Window
    {
        private List<Control> Controls = new List<Control>();

        public EditDialog()
        {
            InitializeComponent();
            Loaded += delegate { KeyboardFocusFirstControl(); };
        }

        public EditDialog(string dialogTitle) : this()
        {
            Title = dialogTitle;
        }

        private void ButtonOK_Click(object sender, RoutedEventArgs e)
        {
            (sender as Button).Focus();
            if (!IsValid(this))
            {
                MessageBox.Show("Some inputs are currently invalid.");
                return;
            }
            DialogResult = true;
        }

        private void ButtonCancel_Click(object sender, RoutedEventArgs e)
        {
            DialogResult = false;
        }

        bool IsValid(DependencyObject node)
        {
            if (node != null)
            {
                bool isValid = !Validation.GetHasError(node);
                if (!isValid)
                {
                    if (node is IInputElement) Keyboard.Focus((IInputElement)node);
                    return false;
                }
            }
            foreach (object subnode in LogicalTreeHelper.GetChildren(node))
            {
                if (subnode is DependencyObject)
                {
                    if (IsValid((DependencyObject)subnode) == false) return false;
                }
            }
            return true;
        }

        public TextBox AddTextBox(string label, ValidationRule validationRule)
        {
            Grid grid = new Grid();
            grid.Height = 25;
            grid.Margin = new Thickness(5);
            ColumnDefinition colDef1 = new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) };
            ColumnDefinition colDef2 = new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) };
            grid.ColumnDefinitions.Add(colDef1);
            grid.ColumnDefinitions.Add(colDef2);

            Label tbLabel = new Label() { Content = label };
            tbLabel.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
            grid.Children.Add(tbLabel);

            TextBox textBox = new TextBox();

            Binding textBinding = new Binding("Text");
            textBinding.Source = textBox;
            textBinding.ValidationRules.Add(validationRule);
            textBox.SetBinding(TextBox.TextProperty, textBinding);

            textBox.GotKeyboardFocus += delegate { textBox.SelectAll(); };
            textBox.TextChanged += delegate { textBox.GetBindingExpression(TextBox.TextProperty).ValidateWithoutUpdate(); };

            textBox.Text = "";
            textBox.GetBindingExpression(TextBox.TextProperty).ValidateWithoutUpdate();

            Grid.SetColumn(textBox, 1);
            grid.Children.Add(textBox);

            StackPanelInput.Children.Add(grid);
            Controls.Add(textBox);
            return textBox;
        }

        public TextBox AddTextBox(string label, ValidationRule validationRule, string defaultText)
        {
            TextBox tb = AddTextBox(label, validationRule);
            tb.Text = defaultText;
            return tb;
        }

        public CheckBox AddCheckBox(string label)
        {
            Grid grid = new Grid();
            grid.Height = 25;
            grid.Margin = new Thickness(5);

            CheckBox cb = new CheckBox();
            cb.VerticalAlignment = System.Windows.VerticalAlignment.Center;
            cb.Content = label;

            grid.Children.Add(cb);

            StackPanelInput.Children.Add(grid);
            Controls.Add(cb);
            return cb;
        }

        private void KeyboardFocusFirstControl()
        {
            if (Controls.Count > 0)
            {
                Keyboard.Focus(Controls[0]);
            }
        }
    }

Usage example:

EditDialog diag = new EditDialog();
TextBox firstName = diag.AddTextBox("First Name:", new StringValidationRule());
TextBox lastName = diag.AddTextBox("Last Name:", new StringValidationRule());
TextBox age = diag.AddTextBox("Age:", new IntegerValidationRule(1,int.MaxValue));
if ((bool)diag.ShowDialog())
{
    //parse texts and write them to some data;
}

With some custom constructors, edit buttons and the like i am sure you'll be able to turn it into a fully dynamic dialogue. Depending on how sophisticated the layout should be that might be more or less work. Of course finding a library that does just that would be easiest, maybe someone else knows one.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号