如何在PropertyGrid中自定义控件

本篇文章为大家展示了如何在PropertyGrid中自定义控件,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。

创新互联公司是一家专注于网站建设、成都网站制作与策划设计,金堂县网站建设哪家好?创新互联公司做网站,专注于网站建设10年,网设计领域的专业建站公司;建站业务涵盖:金堂县等地区。金堂县做网站价格咨询:18982081108

1.创建一个CustomPropertyGrid自定义控件:


  
    
      
        
        
      
    
  
  
    
    
    
    
  

该控件使用的资源字典如下:



  
  

  
    
  
  
    
  

  
  
    
    
    
    
  
  
    
    
  

  
    
  
  
    
    
    
  

  
  
    
    
    
      
      
    
    
    
  

  
    
  

2.编写对应的模板选择类 DynamicallyAssignDataEditorsTemplateSelector:

using DevExpress.Xpf.Editors;
using DevExpress.Xpf.PropertyGrid;
using System.ComponentModel;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;

namespace PropertyGridDemo.PropertyGridControl
{
  public class DynamicallyAssignDataEditorsTemplateSelector : DataTemplateSelector
  {
    private PropertyDescriptor _property = null;
    private RootPropertyDefinition _element = null;
    private PropertyDataContext _propertyDataContext => App.PropertyGridDataContext;

    /// 
    /// 当重写在派生类中,返回根据自定义逻辑的  。
    /// 
    /// 数据对象可以选择模板。
    /// 数据对象。
    /// 
    /// 返回  或 null。默认值为 null。
    /// 
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
      _element = (RootPropertyDefinition)container;
      DataTemplate resource = TryCreateResource(item);
      return resource ?? base.SelectTemplate(item, container);
    }

    /// 
    /// Tries the create resource.
    /// 
    /// The item.
    /// 
    private DataTemplate TryCreateResource(object item)
    {
      if (!(item is PropertyDescriptor)) return null;
      PropertyDescriptor pd = (PropertyDescriptor)item;
      _property = pd;
      var customUIAttribute = (CustomUIAttribute)pd.Attributes[typeof(CustomUIAttribute)];
      if (customUIAttribute == null) return null;
      var customUIType = customUIAttribute.CustomUI;
      return CreatePropertyDefinitionTemplate(customUIAttribute);
    }

    /// 
    /// Gets the data context.
    /// 
    /// Name of the data context property.
    /// 
    private object GetDataContext(string dataContextPropertyName)
    {
      PropertyInfo property = _propertyDataContext?.GetType().GetProperty(dataContextPropertyName);
      if (property == null) return null;
      return property.GetValue(_propertyDataContext, null);
    }

    /// 
    /// Creates the slider data template.
    /// 
    /// The custom UI attribute.
    /// 
    private DataTemplate CreateSliderDataTemplate(CustomUIAttribute customUIAttribute)
    {
      DataTemplate ct = new DataTemplate();
      ct.VisualTree = new FrameworkElementFactory(typeof(StackPanel));
      ct.VisualTree.SetValue(StackPanel.DataContextProperty, GetDataContext(customUIAttribute.DataContextPropertyName));

      FrameworkElementFactory sliderFactory = new FrameworkElementFactory(typeof(Slider));
      sliderFactory.SetBinding(Slider.MaximumProperty, new Binding(nameof(SliderUIDataContext.Max)));
      sliderFactory.SetBinding(Slider.MinimumProperty, new Binding(nameof(SliderUIDataContext.Min)));
      sliderFactory.SetBinding(Slider.SmallChangeProperty, new Binding(nameof(SliderUIDataContext.SmallChange)));
      sliderFactory.SetBinding(Slider.LargeChangeProperty, new Binding(nameof(SliderUIDataContext.LargeChange)));
      sliderFactory.SetBinding(Slider.ValueProperty, new Binding(nameof(SliderUIDataContext.Value)));
      ct.VisualTree.AppendChild(sliderFactory);

      FrameworkElementFactory textFacotry = new FrameworkElementFactory(typeof(TextBlock), "TextBlock");
      textFacotry.SetValue(TextBlock.TextProperty, new Binding(nameof(SliderUIDataContext.Value)));
      //textBoxFactory.AddHandler(TextBox.IsVisibleChanged, new DependencyPropertyChangedEventHandler(SearchBoxVisibleChanged));
      ct.VisualTree.AppendChild(textFacotry);
      ct.Seal();
      return ct;
    }

    /// 
    /// Creates the ComboBox edit template.
    /// 
    /// The custom UI attribute.
    /// 
    private DataTemplate CreateComboBoxEditTemplate(CustomUIAttribute customUIAttribute)
    {
      DataTemplate template = new DataTemplate();
      template.VisualTree = new FrameworkElementFactory(typeof(DockPanel));
      template.VisualTree.SetValue(DockPanel.DataContextProperty, GetDataContext(customUIAttribute.DataContextPropertyName));

      FrameworkElementFactory textFactory = new FrameworkElementFactory(typeof(TextBlock)) ;
      textFactory.SetValue(TextBlock.TextProperty, new Binding(nameof(ComboBoxEditDataContext.Name)));
      template.VisualTree.AppendChild(textFactory);

      FrameworkElementFactory comboBoxEditFactory = new FrameworkElementFactory(typeof(ComboBoxEdit));
      comboBoxEditFactory.SetBinding(ComboBoxEdit.ItemsSourceProperty, new Binding(nameof(ComboBoxEditDataContext.ItemSource)));
      comboBoxEditFactory.SetBinding(ComboBoxEdit.EditValueProperty, new Binding(nameof(ComboBoxEditDataContext.EditValue)));
      comboBoxEditFactory.SetBinding(ComboBoxEdit.SelectedIndexProperty, new Binding(nameof(ComboBoxEditDataContext.SelectedIndex)));
      comboBoxEditFactory.SetValue(ComboBoxEdit.ItemTemplateProperty, (DataTemplate)_element.TryFindResource("ComboBoxEditItemTemplate"));
      template.VisualTree.AppendChild(comboBoxEditFactory);
      template.Seal();
      return template;
    }

    /// 
    /// Creates the property definition template.
    /// 
    /// The custom UI attribute.
    /// 
    private DataTemplate CreatePropertyDefinitionTemplate(CustomUIAttribute customUIAttribute)
    {
      DataTemplate dataTemplate = new DataTemplate();
      DataTemplate cellTemplate = null;//单元格模板
      FrameworkElementFactory factory = new FrameworkElementFactory(typeof(PropertyDefinition));
      dataTemplate.VisualTree = factory;
      switch (customUIAttribute.CustomUI)
      {
        case CustomUITypes.Slider:
          cellTemplate = CreateSliderDataTemplate(customUIAttribute); break;
          //cellTemplate = (DataTemplate)_element.TryFindResource("SliderTemplate");break;
        case CustomUITypes.ComboBoxEit:
          cellTemplate = CreateComboBoxEditTemplate(customUIAttribute);break;
        
      }

      if (cellTemplate != null)
      {
        factory.SetValue(PropertyDefinition.CellTemplateProperty, cellTemplate);
        dataTemplate.Seal();

      }
      else
      {
        return null;
      }
      return dataTemplate;
    }
  }
}
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;

namespace PropertyGridDemo.PropertyGridControl
{
  /// 
  ///初始化所有属性并调用模板选择器进行匹配
  /// 
  public class DataEditorsViewModel
  {
    public IEnumerable Properties { get { return TypeDescriptor.GetProperties(typeof(TestPropertyGrid)).Cast(); } }
  }
}

3.编写一个可用于构建模板的属性 CustomUIType:

using System;

namespace PropertyGridDemo.PropertyGridControl
{
  public class CustomUIType
  {

  }

  public enum CustomUITypes
  {
    Slider,
    ComboBoxEit,
    SpinEdit,
    CheckBoxEdit
  }

  [AttributeUsage(AttributeTargets.Property)]
  internal class CustomUIAttribute : Attribute
  {
    public string DataContextPropertyName { get; set; }
    public CustomUITypes CustomUI { get; set; }
    /// 
    /// 自定义控件属性构造函数
    /// 
    /// The UI types.
    /// Name of the data context property.
    internal CustomUIAttribute(CustomUITypes uiTypes, string dataContextPropertyName)
    {
      CustomUI = uiTypes;
      DataContextPropertyName = dataContextPropertyName;
    }
  }

}

4.编写对应的DataContext类 TestPropertyGrid:

using DevExpress.Mvvm.DataAnnotations;
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Timers;
using System.Windows;

namespace PropertyGridDemo.PropertyGridControl
{
  [MetadataType(typeof(DynamicallyAssignDataEditorsMetadata))]
  public class TestPropertyGrid : PropertyDataContext
  {
    private double _count = 0;
    private SliderUIDataContext _countSource = null;
    private ComboBoxEditDataContext _comboSource = null;
    private double _value=1;

    public TestPropertyGrid()
    {
      Password = "1111111";
      Notes = "Hello";
      Text = "Hello hi";
    }

    [Browsable(false)]
    public SliderUIDataContext CountSource
    {
      get
      {
        if (_countSource != null)
        {

          return _countSource;
        }
        else
        {
          _countSource = new SliderUIDataContext(0, 100, Count, 0.1, 1);
          _countSource.PropertyChanged += (object o, PropertyChangedEventArgs e) =>
          {
            this.Count = _countSource.Value;
          };
          return _countSource;
        }
      }
    }

    [Browsable(false)]
    public ComboBoxEditDataContext ComboSource
    {
      get
      {
        if(_comboSource==null)
        {
          _comboSource =new ComboBoxEditDataContext(ComboBoxEditItemSource.TestItemSource,Value);
          _comboSource.PropertyChanged += (object o, PropertyChangedEventArgs e) =>
           {
             this.Value =Convert.ToDouble(_comboSource.EditValue.Item2); 
           };
          
        }
        return _comboSource;
      }
    }

    [Display(Name = "SliderEdit", GroupName = "CustomUI")]
    [CustomUI(CustomUITypes.Slider, nameof(CountSource))]
    public double Count
    {
      get => _count;
      set
      {
        _count = value;
        CountSource.Value = value; 
        RaisePropertyChanged(nameof(Count));
      }
    }

    [Display(Name = "ComboBoxEditItem", GroupName = "CustomUI")]
    [CustomUI(CustomUITypes.ComboBoxEit, nameof(ComboSource))]
    public double Value
    {
      get => _value;
      set
      {
        if (_value == value) return;
        _value = value;
        //ComboSource.Value = value;
        RaisePropertyChanged(nameof(Value));
      }
    }

    [Display(Name = "Password", GroupName = "DefaultUI")]
    public string Password { get; set; }

    [Display(Name = "TextEdit", GroupName = "DefaultUI")]
    public string Text { get; set; }

    [Display(Name = "Notes", GroupName = "DefaultUI")]
    public string Notes { get; set; }


    [Display(Name = "Double", GroupName = "DefaultUI")]
    [DefaultValue(1)]
    public double TestDouble { get; set; }

    [Display(Name = "Items", GroupName = "DefaultUI")]
    [DefaultValue(Visibility.Visible)]
    public Visibility TestItems { get; set; }
  }

  public static class DynamicallyAssignDataEditorsMetadata
  {
    public static void BuildMetadata(MetadataBuilder builder)
    {
      builder.Property(x => x.Password)
        .PasswordDataType();

      builder.Property(x => x.Notes)
        .MultilineTextDataType();
    }
  }
}

 该类中用到的其他类主要有以下几个,以下几个类主要用于数据绑定:

 namespace PropertyGridDemo.PropertyGridControl
{
  public class SliderUIDataContext:PropertyDataContext
  {
    private double _value = 0;
    private double _max = 0;
    private double _min = 0;
    private double _smallChange = 1;
    private double _largeChange=1;

    public SliderUIDataContext()
    {

    }

    /// 
    /// Initializes a new instance of the  class.
    /// 
    /// The minimum.
    /// The maximum.
    /// The value.
    /// The small change.
    /// The large change.
    public SliderUIDataContext(double min, double max, double value,double smallChange=0.01,double largeChange=0.1)
    {
      SmallChange = smallChange;
      LargeChange = largeChange;
      Max = max;
      Min = min;
      Value = value;
    }

    /// 
    /// Gets or sets the small change.
    /// 
    /// 
    /// The small change.
    /// 
    public double SmallChange
    {
      get => _smallChange;
      set
      {
        if (value == _min) return;
        _min = value;
        RaisePropertyChanged(nameof(SmallChange));
      }
    }

    /// 
    /// Gets or sets the large change.
    /// 
    /// 
    /// The large change.
    /// 
    public double LargeChange
    {
      get => _largeChange;
      set
      {
        if (Value == _largeChange) return;
        _largeChange = value;
        RaisePropertyChanged(nameof(LargeChange));
      }
    }


    /// 
    /// Gets or sets the maximum.
    /// 
    /// 
    /// The maximum.
    /// 
    public double Max
    {
      get => _max;
      set
      {
        if (value == _max) return;
        _max = value;
        RaisePropertyChanged(nameof(Max));
      }
    }

    /// 
    /// Gets or sets the minimum.
    /// 
    /// 
    /// The minimum.
    /// 
    public double Min
    {
      get => _min;
      set
      {
        if (value == _min) return;
        _min = value;
        RaisePropertyChanged(nameof(Min));
      }
    }

    /// 
    /// Gets or sets the value.
    /// 
    /// 
    /// The value.
    /// 
    public double Value
    {
      get => _value;
      set
      {
        if (value == _value) return;
        _value = value;
        RaisePropertyChanged(nameof(Value));
      }
    }
  }
}
using System;
using System.Linq;

namespace PropertyGridDemo.PropertyGridControl
{
  public class ComboBoxEditDataContext:PropertyDataContext
  {
    private Tuple[] _itemSource;
    private Tuple _editValue;
    private int _selectedIndex;

    /// 
    /// Initializes a new instance of the  class.
    /// 
    /// The item source.
    /// The edit value.
    public ComboBoxEditDataContext(Tuple[] itemSource,Tuple editValue)
    {
      _itemSource = itemSource;
      _editValue = _itemSource.FirstOrDefault(x => x?.Item1.ToString() == editValue?.Item1.ToString() && x?.Item2?.ToString() == x?.Item2?.ToString());
    }

    /// 
    /// Initializes a new instance of the  class.
    /// 
    /// The item source.
    /// The value.
    public ComboBoxEditDataContext(Tuple[] itemSource, object value)
    {
      _itemSource = itemSource;
      _editValue = _itemSource.FirstOrDefault(x => x?.Item2.ToString() == value.ToString() );
    }

    public string Name
    {
      get;set;
    }

    /// 
    /// Gets or sets the item source.
    /// 
    /// 
    /// The item source.
    /// 
    public Tuple[] ItemSource
    {
      get => _itemSource;
      set
      {
        //if (_itemSource == value) return;
        _itemSource = value;
        RaisePropertyChanged(nameof(ItemSource));
      }
    }

    /// 
    /// Gets or sets the edit value.
    /// 
    /// 
    /// The edit value.
    /// 
    public Tuple EditValue
    {
      get => _editValue;
      set
      {
        if (_editValue == value) return;
        _editValue = value;
        RaisePropertyChanged(nameof(EditValue));
      }
    }

    public object Value
    {
      set
      {
        EditValue = ItemSource.FirstOrDefault(x => x.Item2.Equals(value));
      }
    }

    /// 
    /// Gets or sets the index of the selected.
    /// 
    /// 
    /// The index of the selected.
    /// 
    public int SelectedIndex
    {
      get => _selectedIndex;
      set
      {
        if (_selectedIndex == value || value==-1) return;
        _selectedIndex = value;
        EditValue = ItemSource[value];
        RaisePropertyChanged(nameof(SelectedIndex));
      }
    }
  }
}
using System.ComponentModel;

namespace PropertyGridDemo.PropertyGridControl
{
  public class PropertyDataContext:INotifyPropertyChanged
  {
    /// 
    /// 在更改属性值时发生。
    /// 
    public event PropertyChangedEventHandler PropertyChanged;

    /// 
    /// 触发属性变化
    /// 
    /// 
    public virtual void RaisePropertyChanged(string propertyName)
    {
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
  }
}
using System;

namespace PropertyGridDemo.PropertyGridControl
{
  internal static class ComboBoxEditItemSource
  {
    internal static Tuple[] TestItemSource = new Tuple[] {
      new Tuple("1",1),
      new Tuple("2",2),
      new Tuple("3",3)
    };
  }
}

5.将以上的CustomPropertyGrid丢进容器中即可,这里我直接用Mainwindow来演示:


  
    
      
      
    

    
    
  

运行示意图:

如何在PropertyGrid中自定义控件

上述内容就是如何在PropertyGrid中自定义控件,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注创新互联行业资讯频道。


本文题目:如何在PropertyGrid中自定义控件
文章分享:http://myzitong.com/article/ghjche.html