コード例 #1
0
ファイル: FormEditObject.cs プロジェクト: Slion/CIC
        /// <summary>
        /// Create a control for the given property.
        /// TODO: Handle cases where a property value is null. That can be the case when extending an existing class and loading it from an older save.
        /// Though I guess that should really be taken care of in Ear.Object.Construct which is called once the object was internalized.
        /// </summary>
        /// <param name="aInfo"></param>
        /// <param name="aAttribute"></param>
        /// <param name="aObject"></param>
        /// <returns></returns>
        private Control CreateControlForProperty(PropertyInfo aInfo, AttributeObjectProperty aAttribute, T aObject)
        {
            if (aInfo.PropertyType == typeof(int) || aInfo.PropertyType == typeof(float))
            {
                //Integer properties are using numeric editor
                NumericUpDown ctrl = new NumericUpDown();
                ctrl.AutoSize = true;
                //ctrl.Dock = DockStyle.Fill; // Fill the whole table cell
                ctrl.Minimum       = (decimal)aAttribute.Minimum;
                ctrl.Maximum       = (decimal)aAttribute.Maximum;
                ctrl.Increment     = (decimal)aAttribute.Increment;
                ctrl.DecimalPlaces = aAttribute.DecimalPlaces;
                ctrl.Value         = decimal.Parse(aInfo.GetValue(aObject).ToString());
                // Hook-in change notification after setting the value
                ctrl.ValueChanged += ControlValueChanged;
                return(ctrl);
            }
            else if (aInfo.PropertyType.IsEnum)
            {
                //Enum properties are using combo box
                ComboBox ctrl = new ComboBox();
                ctrl.AutoSize      = true;
                ctrl.Sorted        = true;
                ctrl.DropDownStyle = ComboBoxStyle.DropDownList;
                //Data source is fine but it gives us duplicate entries for duplicated enum values
                //ctrl.DataSource = Enum.GetValues(aInfo.PropertyType);

                //Therefore we need to explicitly create our items
                Size cbSize = new Size(0, 0);
                foreach (string name in aInfo.PropertyType.GetEnumNames())
                {
                    ctrl.Items.Add(name.ToString());
                    Graphics g = this.CreateGraphics();
                    //Since combobox autosize would not work we need to measure text ourselves
                    SizeF size = g.MeasureString(name.ToString(), ctrl.Font);
                    cbSize.Width  = Math.Max(cbSize.Width, (int)size.Width);
                    cbSize.Height = Math.Max(cbSize.Height, (int)size.Height);
                }

                cbSize.Width += 10; // Account for margin

                //Make sure our combobox is large enough
                ctrl.MinimumSize = cbSize;

                // Instantiate our enum
                object enumValue = Activator.CreateInstance(aInfo.PropertyType);
                enumValue = aInfo.GetValue(aObject);
                //Set the current item
                ctrl.SelectedItem = enumValue.ToString();
                // Hook-in change notification after setting the value
                ctrl.SelectedIndexChanged += ControlValueChanged;

                return(ctrl);
            }
            else if (aInfo.PropertyType == typeof(bool))
            {
                CheckBox ctrl = new CheckBox();
                ctrl.AutoSize = true;
                ctrl.Text     = aAttribute.Description;
                ctrl.Checked  = (bool)aInfo.GetValue(aObject);
                // Hook-in change notification after setting the value
                ctrl.CheckedChanged += ControlValueChanged;
                return(ctrl);
            }
            else if (aInfo.PropertyType == typeof(string))
            {
                TextBox ctrl = new TextBox();
                ctrl.AutoSize = true;
                ctrl.Dock     = DockStyle.Fill; // Fill the whole table cell
                ctrl.Text     = (string)aInfo.GetValue(aObject);

                // Multiline setup
                ctrl.Multiline = aAttribute.Multiline;
                if (ctrl.Multiline)
                {
                    ctrl.AcceptsReturn = true;
                    ctrl.ScrollBars    = ScrollBars.Vertical;
                    // Adjust our height as needed
                    Size size = ctrl.Size;
                    size.Height     += ctrl.Font.Height * (aAttribute.HeightInLines - 1);
                    ctrl.MinimumSize = size;
                }

                // Hook-in change notification after setting the value
                ctrl.TextChanged += ControlValueChanged;
                return(ctrl);
            }
            else if (aInfo.PropertyType == typeof(PropertyFile))
            {
                // We have a file property
                // Create a button that will trigger the open file dialog to select our file.
                Button ctrl = new Button();
                ctrl.AutoSize = true;
                ctrl.Text     = ((PropertyFile)aInfo.GetValue(aObject)).FullPath;
                // Add lambda expression to Click event
                ctrl.Click += (sender, e) =>
                {
                    // Create open file dialog
                    OpenFileDialog ofd = new OpenFileDialog();
                    ofd.RestoreDirectory = true;
                    // Use file filter specified by our property
                    ofd.Filter = aAttribute.Filter;
                    // Show our dialog
                    if (SharpLib.Forms.DlgBox.ShowDialog(ofd) == DialogResult.OK)
                    {
                        // Fetch selected file name
                        ctrl.Text = ofd.FileName;
                    }
                };

                // Hook-in change notification after setting the value
                ctrl.TextChanged += ControlValueChanged;
                return(ctrl);
            }
            else if (aInfo.PropertyType == typeof(PropertyComboBox))
            {
                //ComboBox property
                PropertyComboBox property = ((PropertyComboBox)aInfo.GetValue(aObject));

                ComboBox ctrl = new ComboBox();
                ctrl.AutoSize = true;
                //ctrl.Sorted = property.Sorted; // Sorted is not supported and does not work using DataSource, can result in the wrong item being selected
                ctrl.DropDownStyle = ComboBoxStyle.DropDownList;
                // Use DataSource with optional DisplayMember and ValueMember, that also works for plain string collection
                ctrl.DisplayMember = property.DisplayMember;
                ctrl.ValueMember   = property.ValueMember;
                //ctrl.DataSource = ((PropertyComboBox)aInfo.GetValue(aObject)).Items;

                UpdateControlFromProperty(ctrl, aInfo, aObject);

                return(ctrl);
            }
            else if (aInfo.PropertyType == typeof(PropertyButton))
            {
                // We have a button property
                // Create a button that will trigger the custom action.
                Button ctrl = new Button();
                ctrl.AutoSize = true;
                ctrl.Text     = ((PropertyButton)aInfo.GetValue(aObject)).Text;
                // Hook in click event
                ctrl.Click += ((PropertyButton)aInfo.GetValue(aObject)).ClickEventHandler;
                // Hook-in change notification after setting the value
                ctrl.TextChanged += ControlValueChanged;
                return(ctrl);
            }
            else if (aInfo.PropertyType == typeof(PropertyCheckedListBox))
            {
                //CheckedListBox property
                PropertyCheckedListBox property = ((PropertyCheckedListBox)aInfo.GetValue(aObject));

                CheckedListBox ctrl = new CheckedListBox();
                ctrl.AutoSize     = true;
                ctrl.Sorted       = property.Sorted;
                ctrl.CheckOnClick = true;

                // Populate our box with list items
                foreach (string item in property.Items)
                {
                    int index = ctrl.Items.Add(item);
                    // Check items if needed
                    if (property.CheckedItems.Contains(item))
                    {
                        ctrl.SetItemChecked(index, true);
                    }
                }
                //
                // Hook-in change notification after setting the value
                // That's essentially making sure title/brief gets updated as items are checked or unchecked
                // This looks convoluted as we are working around the fact that ItemCheck event is triggered before the model is updated.
                // See: https://stackoverflow.com/a/48645552/3969362
                ctrl.ItemCheck += (s, e) => BeginInvoke((MethodInvoker)(() => ControlValueChanged(s, e)));
                return(ctrl);
            }

            //TODO: add support for other control type here
            return(null);
        }
コード例 #2
0
ファイル: FormEditObject.cs プロジェクト: Slion/CIC
        /// <summary>
        /// Update a control states from an edited object property.
        /// This notably enables refresh from our HID device property when the user is recording an event.
        ///
        /// TODO: Add support for needed property types.
        /// </summary>
        /// <param name="aCtrl"></param>
        /// <param name="aInfo"></param>
        /// <param name="aObject"></param>
        private void UpdateControlFromProperty(Control aCtrl, PropertyInfo aInfo, T aObject)
        {
            if (aCtrl == null || aInfo == null || aObject == null)
            {
                // No much we can do then
                return;
            }

            if (aInfo.PropertyType == typeof(PropertyComboBox))
            {
                PropertyComboBox property = ((PropertyComboBox)aInfo.GetValue(aObject));
                ComboBox         ctrl     = (ComboBox)aCtrl;

                // Disable object update to prevent endless update notification circle
                ctrl.SelectedIndexChanged -= ControlValueChanged;
                // In case out items changed
                ctrl.DataSource = property.Items;

                // When using DataSource we need to wait until our items are create to proceed further
                BeginInvoke((MethodInvoker)(() =>
                {
                    // Now our items must have been created from our data source
                    Graphics g = ctrl.CreateGraphics();
                    // Make sure our ComboBox is large enough to display its items
                    Size cbSize = new Size(0, 0);
                    foreach (object item in ctrl.Items)
                    {
                        //Since ComboBox AutoSize would not work we need to measure text ourselves
                        SizeF size = g.MeasureString(string.IsNullOrEmpty(property.DisplayMember) ?
                                                     // Typically the case for string collection DataSource
                                                     item.ToString() :
                                                     // DataSource is a collection of unknown objects, using reflection we fetch the property referred to by DisplayMember then
                                                     item.GetType().GetProperty(property.DisplayMember).GetValue(item).ToString(), ctrl.Font);

                        cbSize.Width = Math.Max(cbSize.Width, (int)size.Width);
                        cbSize.Height = Math.Max(cbSize.Height, (int)size.Height);
                    }
                    cbSize.Width += 10; // Account for margin
                    //Make sure our combobox is large enough
                    ctrl.MinimumSize = cbSize;

                    //

                    if (!string.IsNullOrEmpty(property.CurrentItem)) // Defensive, I guess
                    {
                        //if (!property.CurrentItemNotFound)
                        {
                            // We can't set SelectedValue when no ValueMember
                            if (string.IsNullOrEmpty(property.ValueMember))
                            {
                                // Use plain SelectedItem when no ValueMember, typically the case when simply using a string collection as DataSource
                                ctrl.SelectedItem = property.CurrentItem;
                            }
                            else
                            {
                                // We have a ValueMember typically the case when our DataSource is a collection of unknown objects
                                // We need to set our current item using value rather then display name
                                ctrl.SelectedValue = property.CurrentItem;
                            }
                        }
                    }

                    // Hook-in change notification after setting the value
                    // That makes sure object is updated when user changes our control
                    ctrl.SelectedIndexChanged += ControlValueChanged;
                }));
            }
        }
コード例 #3
0
ファイル: FormEditObject.cs プロジェクト: Slion/CIC
        /// <summary>
        /// Set an object property value from the state of the given control.
        ///
        /// Extend this function to support reading new types of properties.
        /// </summary>
        /// <param name="aObject"></param>
        private static void SetObjectPropertyValueFromControl(T aObject, PropertyInfo aInfo, Control aControl)
        {
            if (aInfo.PropertyType == typeof(int))
            {
                NumericUpDown ctrl = (NumericUpDown)aControl;
                aInfo.SetValue(aObject, (int)ctrl.Value);
            }
            else if (aInfo.PropertyType == typeof(float))
            {
                NumericUpDown ctrl = (NumericUpDown)aControl;
                aInfo.SetValue(aObject, (float)ctrl.Value);
            }
            else if (aInfo.PropertyType.IsEnum)
            {
                // Instantiate our enum
                object enumValue = Activator.CreateInstance(aInfo.PropertyType);
                // Parse our enum from combo box
                enumValue = Enum.Parse(aInfo.PropertyType, ((ComboBox)aControl).SelectedItem.ToString());
                //enumValue = ((ComboBox)aControl).SelectedValue;
                // Set enum value
                aInfo.SetValue(aObject, enumValue);
            }
            else if (aInfo.PropertyType == typeof(bool))
            {
                CheckBox ctrl = (CheckBox)aControl;
                aInfo.SetValue(aObject, ctrl.Checked);
            }
            else if (aInfo.PropertyType == typeof(string))
            {
                TextBox ctrl = (TextBox)aControl;
                aInfo.SetValue(aObject, ctrl.Text);
            }
            else if (aInfo.PropertyType == typeof(PropertyFile))
            {
                Button       ctrl  = (Button)aControl;
                PropertyFile value = new PropertyFile {
                    FullPath = ctrl.Text
                };
                aInfo.SetValue(aObject, value);
            }
            else if (aInfo.PropertyType == typeof(PropertyComboBox))
            {
                ComboBox ctrl = (ComboBox)aControl;
                if (ctrl.SelectedItem != null)
                {
                    // Apparently you can still get the SelectedValue even when no ValueMember was set
                    string           currentItem = ctrl.SelectedValue.ToString();
                    PropertyComboBox value       = (PropertyComboBox)aInfo.GetValue(aObject);
                    // Make sure the value actually changed before doing anything
                    // Shall we do that for every control?
                    if (value.CurrentItem != currentItem)
                    {
                        value.CurrentItem = currentItem;
                        //Not strictly needed but makes sure the set method is called
                        aInfo.SetValue(aObject, value);
                        //
                        aObject.OnPropertyChanged(aInfo.Name);
                    }
                }
            }
            else if (aInfo.PropertyType == typeof(PropertyButton))
            {
                Button         ctrl  = (Button)aControl;
                PropertyButton value = new PropertyButton {
                    Text = ctrl.Text
                };
                aInfo.SetValue(aObject, value);
            }
            else if (aInfo.PropertyType == typeof(PropertyCheckedListBox))
            {
                CheckedListBox         ctrl         = (CheckedListBox)aControl;
                PropertyCheckedListBox value        = (PropertyCheckedListBox)aInfo.GetValue(aObject);
                List <string>          checkedItems = new List <string>();
                foreach (string item in ctrl.CheckedItems)
                {
                    checkedItems.Add(item);
                }
                value.CheckedItems = checkedItems;

                //value.CurrentItem = currentItem;
                //Not strictly needed but makes sure the set method is called
                aInfo.SetValue(aObject, value);
                //
                //aObject.OnPropertyChanged(aInfo.Name);
            }

            //TODO: add support for other types here
        }