首頁 > 後端開發 > C#.Net教程 > 一個很強大的控制項--PropertyGrid

一個很強大的控制項--PropertyGrid

零下一度
發布: 2017-06-24 09:49:13
原創
6096 人瀏覽過

PropertyGrid是一個很強大的控件,使用該控制項做屬性設定面板的一個好處是你只需要專注於程式碼而無需關注UI的呈現,PropertyGrid會預設根據變數類型選擇合適的控制項顯示。但這也帶來了一個問題,就是控件的使用變得不是特別靈活,主要表現在你無法根據你的需求很好的選擇控件,比如當你需要用Slider控件來設置int型變量時,PropertyGrid默認的模板選擇器是不支援的。網路上找了許多資料基本上都是介紹WinForm的實現方式,主要用到了IWindowFromService這個接口,並未找到合適的適合WPF的Demo,後來在參考了DEVExpress的官方Demo之後我做了一個基於WPF和DEV 16.2的PropertyGrid Demo,基本上實作了上述功能。

為了實現這一點,需要自訂一個DataTemplateSeletor類,這也是本文的核心程式碼。

1.建立一個CustomPropertyGrid自訂控制項:

 1 <UserControl 2     x:Class="PropertyGridDemo.PropertyGridControl.CustomPropertyGrid" 3     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 6     xmlns:dxprg="http://schemas.devexpress.com/winfx/2008/xaml/propertygrid" 7     xmlns:local="clr-namespace:PropertyGridDemo.PropertyGridControl" 8     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 9     d:DesignHeight="300"10     d:DesignWidth="300"11     mc:Ignorable="d">12     <UserControl.Resources>13         <ResourceDictionary>14             <ResourceDictionary.MergedDictionaries>15                 <!--  资源字典  -->16                 <ResourceDictionary Source="../PropertyGridControl/DynamicallyAssignDataEditorsResources.xaml" />17             </ResourceDictionary.MergedDictionaries>18         </ResourceDictionary>19     </UserControl.Resources>20     <Grid>21         <!--  PropertyDefinitionStyle:定义属性描述的风格模板  -->22         <!--  PropertyDefinitionTemplateSelector:定义一个模板选择器,对应一个继承自DataTemplateSelector的类  -->23         <!--  PropertyDefinitionsSource:定义一个获取数据属性集合的类,对应一个自定义类(本Demo中对应DataEditorsViewModel)  -->24         <dxprg:PropertyGridControl25             x:Name="PropertyGridControl"26             Margin="24"27             DataContextChanged="PropertyGridControl_DataContextChanged"28             ExpandCategoriesWhenSelectedObjectChanged="True"29             PropertyDefinitionStyle="{StaticResource DynamicallyAssignDataEditorsPropertyDefinitionStyle}"30             PropertyDefinitionTemplateSelector="{StaticResource DynamicallyAssignDataEditorsTemplateSelector}"31             PropertyDefinitionsSource="{Binding Path=Properties, Source={StaticResource DemoDataProvider}}"32             ShowCategories="True"33             ShowDescriptionIn="Panel" />34     </Grid>35 </UserControl>
登入後複製
CustomPropertyGrid

 此控制項使用的資源字典如下:

 1 <ResourceDictionary 2     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5     xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors" 6     xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid" 7     xmlns:dxprg="http://schemas.devexpress.com/winfx/2008/xaml/propertygrid" 8     xmlns:local="clr-namespace:PropertyGridDemo.PropertyGridControl" 9     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"10     mc:Ignorable="d">11 12     <local:DynamicallyAssignDataEditorsTemplateSelector x:Key="DynamicallyAssignDataEditorsTemplateSelector" />13     <local:DataEditorsViewModel x:Key="DemoDataProvider" />14 15     <DataTemplate x:Key="DescriptionTemplate">16         <RichTextBox17             x:Name="descriptionRichTextBox"18             MinWidth="150"19             HorizontalContentAlignment="Stretch"20             Background="Transparent"21             BorderThickness="0"22             Foreground="{Binding Path=(TextElement.Foreground), RelativeSource={RelativeSource TemplatedParent}}"23             IsReadOnly="True"24             IsTabStop="False" />25     </DataTemplate>26     <DataTemplate x:Key="descriptionTemplate">27         <RichTextBox28             x:Name="descriptionRichTextBox"29             MinWidth="150"30             HorizontalContentAlignment="Stretch"31             Background="Transparent"32             BorderThickness="0"33             Foreground="{Binding Path=(TextElement.Foreground), RelativeSource={RelativeSource TemplatedParent}}"34             IsReadOnly="True"35             IsTabStop="False" />36     </DataTemplate>37 38     <!--  设置控件的全局样式和数据绑定  -->39     <Style x:Key="DynamicallyAssignDataEditorsPropertyDefinitionStyle" TargetType="dxprg:PropertyDefinition">40         <Setter Property="Path" Value="{Binding Name}" />41         <!--<Setter Property="Header" Value="{Binding Converter={StaticResource PropertyDescriptorToDisplayNameConverter}}"/>-->42         <Setter Property="Description" Value="{Binding}" />43         <Setter Property="DescriptionTemplate" Value="{StaticResource descriptionTemplate}" />44     </Style>45     <Style x:Key="DescriptionContainerStyle" TargetType="dxprg:PropertyDescriptionPresenterControl">46         <Setter Property="ShowSelectedRowHeader" Value="False" />47         <Setter Property="MinHeight" Value="70" />48     </Style>49 50     <Style TargetType="Slider">51         <Setter Property="Margin" Value="2" />52     </Style>53     <Style TargetType="dxe:ComboBoxEdit">54         <Setter Property="IsTextEditable" Value="False" />55         <Setter Property="ApplyItemTemplateToSelectedItem" Value="True" />56         <Setter Property="Margin" Value="2" />57     </Style>58 59     <!--  测试直接从DataTemplate获取控件  -->60     <DataTemplate x:Key="SliderTemplate" DataType="local:SliderExtend">61         <!--<dxprg:PropertyDefinition>62             <dxprg:PropertyDefinition.CellTemplate>-->63         <!--<DataTemplate>-->64         <StackPanel x:Name="Root">65             <Slider66                 Maximum="{Binding Path=Max}"67                 Minimum="{Binding Path=Min}"68                 Value="{Binding Path=Value}" />69             <TextBlock Text="{Binding Path=Value}" />70         </StackPanel>71         <!--</DataTemplate>-->72         <!--</dxprg:PropertyDefinition.CellTemplate>73         </dxprg:PropertyDefinition>-->74     </DataTemplate>75 76     <DataTemplate x:Key="ComboBoxEditItemTemplate" DataType="Tuple">77         <TextBlock78             Height="20"79             Margin="5,3,0,0"80             VerticalAlignment="Center"81             Text="{Binding Item1}" />82     </DataTemplate>83 </ResourceDictionary>
登入後複製
ResourceDictionary

2.編寫對應的範本選擇類別DynamicallyAssignDataEditorsTemplateSelector:

  1 using DevExpress.Xpf.Editors;  2 using DevExpress.Xpf.PropertyGrid;  3 using System.ComponentModel;  4 using System.Reflection;  5 using System.Windows;  6 using System.Windows.Controls;  7 using System.Windows.Data;  8   9 namespace PropertyGridDemo.PropertyGridControl 10 { 11     public class DynamicallyAssignDataEditorsTemplateSelector : DataTemplateSelector 12     { 13         private PropertyDescriptor _property = null; 14         private RootPropertyDefinition _element = null; 15         private PropertyDataContext _propertyDataContext => App.PropertyGridDataContext; 16  17         /// <summary> 18         /// 当重写在派生类中,返回根据自定义逻辑的 <see cref="T:System.Windows.DataTemplate" /> 。 19         /// </summary> 20         /// <param name="item">数据对象可以选择模板。</param> 21         /// <param name="container">数据对象。</param> 22         /// <returns> 23         /// 返回 <see cref="T:System.Windows.DataTemplate" /> 或 null。默认值为 null。 24         /// </returns> 25         public override DataTemplate SelectTemplate(object item, DependencyObject container) 26         { 27             _element = (RootPropertyDefinition)container; 28             DataTemplate resource = TryCreateResource(item); 29             return resource ?? base.SelectTemplate(item, container); 30         } 31  32         /// <summary> 33         /// Tries the create resource. 34         /// </summary> 35         /// <param name="item">The item.</param> 36         /// <returns></returns> 37         private DataTemplate TryCreateResource(object item) 38         { 39             if (!(item is PropertyDescriptor)) return null; 40             PropertyDescriptor pd = (PropertyDescriptor)item; 41             _property = pd; 42             var customUIAttribute = (CustomUIAttribute)pd.Attributes[typeof(CustomUIAttribute)]; 43             if (customUIAttribute == null) return null; 44             var customUIType = customUIAttribute.CustomUI; 45             return CreatePropertyDefinitionTemplate(customUIAttribute); 46         } 47  48         /// <summary> 49         /// Gets the data context. 50         /// </summary> 51         /// <param name="dataContextPropertyName">Name of the data context property.</param> 52         /// <returns></returns> 53         private object GetDataContext(string dataContextPropertyName) 54         { 55             PropertyInfo property = _propertyDataContext?.GetType().GetProperty(dataContextPropertyName); 56             if (property == null) return null; 57             return property.GetValue(_propertyDataContext, null); 58         } 59  60         /// <summary> 61         /// Creates the slider data template. 62         /// </summary> 63         /// <param name="customUIAttribute">The custom UI attribute.</param> 64         /// <returns></returns> 65         private DataTemplate CreateSliderDataTemplate(CustomUIAttribute customUIAttribute) 66         { 67             DataTemplate ct = new DataTemplate(); 68             ct.VisualTree = new FrameworkElementFactory(typeof(StackPanel)); 69             ct.VisualTree.SetValue(StackPanel.DataContextProperty, GetDataContext(customUIAttribute.DataContextPropertyName)); 70  71             FrameworkElementFactory sliderFactory = new FrameworkElementFactory(typeof(Slider)); 72             sliderFactory.SetBinding(Slider.MaximumProperty, new Binding(nameof(SliderUIDataContext.Max))); 73             sliderFactory.SetBinding(Slider.MinimumProperty, new Binding(nameof(SliderUIDataContext.Min))); 74             sliderFactory.SetBinding(Slider.SmallChangeProperty, new Binding(nameof(SliderUIDataContext.SmallChange))); 75             sliderFactory.SetBinding(Slider.LargeChangeProperty, new Binding(nameof(SliderUIDataContext.LargeChange))); 76             sliderFactory.SetBinding(Slider.ValueProperty, new Binding(nameof(SliderUIDataContext.Value))); 77             ct.VisualTree.AppendChild(sliderFactory); 78  79             FrameworkElementFactory textFacotry = new FrameworkElementFactory(typeof(TextBlock), "TextBlock"); 80             textFacotry.SetValue(TextBlock.TextProperty, new Binding(nameof(SliderUIDataContext.Value))); 81             //textBoxFactory.AddHandler(TextBox.IsVisibleChanged, new DependencyPropertyChangedEventHandler(SearchBoxVisibleChanged)); 82             ct.VisualTree.AppendChild(textFacotry); 83             ct.Seal(); 84             return ct; 85         } 86  87         /// <summary> 88         /// Creates the ComboBox edit template. 89         /// </summary> 90         /// <param name="customUIAttribute">The custom UI attribute.</param> 91         /// <returns></returns> 92         private DataTemplate CreateComboBoxEditTemplate(CustomUIAttribute customUIAttribute) 93         { 94             DataTemplate template = new DataTemplate(); 95             template.VisualTree = new FrameworkElementFactory(typeof(DockPanel)); 96             template.VisualTree.SetValue(DockPanel.DataContextProperty, GetDataContext(customUIAttribute.DataContextPropertyName)); 97  98             FrameworkElementFactory textFactory = new FrameworkElementFactory(typeof(TextBlock)) ; 99             textFactory.SetValue(TextBlock.TextProperty, new Binding(nameof(ComboBoxEditDataContext.Name)));100             template.VisualTree.AppendChild(textFactory);101 102             FrameworkElementFactory comboBoxEditFactory = new FrameworkElementFactory(typeof(ComboBoxEdit));103             comboBoxEditFactory.SetBinding(ComboBoxEdit.ItemsSourceProperty, new Binding(nameof(ComboBoxEditDataContext.ItemSource)));104             comboBoxEditFactory.SetBinding(ComboBoxEdit.EditValueProperty, new Binding(nameof(ComboBoxEditDataContext.EditValue)));105             comboBoxEditFactory.SetBinding(ComboBoxEdit.SelectedIndexProperty, new Binding(nameof(ComboBoxEditDataContext.SelectedIndex)));106             comboBoxEditFactory.SetValue(ComboBoxEdit.ItemTemplateProperty, (DataTemplate)_element.TryFindResource("ComboBoxEditItemTemplate"));107             template.VisualTree.AppendChild(comboBoxEditFactory);108             template.Seal();109             return template;110         }111 112         /// <summary>113         /// Creates the property definition template.114         /// </summary>115         /// <param name="customUIAttribute">The custom UI attribute.</param>116         /// <returns></returns>117         private DataTemplate CreatePropertyDefinitionTemplate(CustomUIAttribute customUIAttribute)118         {119             DataTemplate dataTemplate = new DataTemplate();120             DataTemplate cellTemplate = null;//单元格模板121             FrameworkElementFactory factory = new FrameworkElementFactory(typeof(PropertyDefinition));122             dataTemplate.VisualTree = factory;123             switch (customUIAttribute.CustomUI)124             {125                 case CustomUITypes.Slider:126                     cellTemplate = CreateSliderDataTemplate(customUIAttribute); break;127                     //cellTemplate = (DataTemplate)_element.TryFindResource("SliderTemplate");break;128                 case CustomUITypes.ComboBoxEit:129                     cellTemplate = CreateComboBoxEditTemplate(customUIAttribute);break;130                 131             }132 133             if (cellTemplate != null)134             {135                 factory.SetValue(PropertyDefinition.CellTemplateProperty, cellTemplate);136                 dataTemplate.Seal();137 138             }139             else140             {141                 return null;142             }143             return dataTemplate;144         }145     }146 }
登入後複製
DynamicallyAssignDataEditorsTemplateSelector
using System.Collections.Generic;using System.ComponentModel;using System.Linq;namespace PropertyGridDemo.PropertyGridControl
{/// <summary>///初始化所有属性并调用模板选择器进行匹配/// </summary>public class DataEditorsViewModel
    {public IEnumerable<PropertyDescriptor> Properties { get { return TypeDescriptor.GetProperties(typeof(TestPropertyGrid)).Cast<PropertyDescriptor>(); } }
    }
}
登入後複製
DataEditorsViewModel

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; }/// <summary>/// 自定义控件属性构造函数/// </summary>/// <param name="uiTypes">The UI types.</param>/// <param name="dataContextPropertyName">Name of the data context property.</param>internal CustomUIAttribute(CustomUITypes uiTypes, string dataContextPropertyName)
        {
            CustomUI = uiTypes;
            DataContextPropertyName = dataContextPropertyName;
        }
    }

}
登入後複製
CustomUIType

#4 .編寫對應的DataContext類別TestPropertyGrid:

  1 using DevExpress.Mvvm.DataAnnotations;  2 using System;  3 using System.ComponentModel;  4 using System.ComponentModel.DataAnnotations;  5 using System.Timers;  6 using System.Windows;  7   8 namespace PropertyGridDemo.PropertyGridControl  9 { 10     [MetadataType(typeof(DynamicallyAssignDataEditorsMetadata))] 11     public class TestPropertyGrid : PropertyDataContext 12     { 13         private double _count = 0; 14         private SliderUIDataContext _countSource = null; 15         private ComboBoxEditDataContext _comboSource = null; 16         private double _value=1; 17  18         public TestPropertyGrid() 19         { 20             Password = "1111111"; 21             Notes = "Hello"; 22             Text = "Hello hi"; 23         } 24  25         [Browsable(false)] 26         public SliderUIDataContext CountSource 27         { 28             get 29             { 30                 if (_countSource != null) 31                 { 32  33                     return _countSource; 34                 } 35                 else 36                 { 37                     _countSource = new SliderUIDataContext(0, 100, Count, 0.1, 1); 38                     _countSource.PropertyChanged += (object o, PropertyChangedEventArgs e) => 39                     { 40                         this.Count = _countSource.Value; 41                     }; 42                     return _countSource; 43                 } 44             } 45         } 46  47         [Browsable(false)] 48         public ComboBoxEditDataContext ComboSource 49         { 50             get 51             { 52                 if(_comboSource==null) 53                 { 54                     _comboSource =new ComboBoxEditDataContext(ComboBoxEditItemSource.TestItemSource,Value); 55                     _comboSource.PropertyChanged += (object o, PropertyChangedEventArgs e) => 56                       { 57                           this.Value =Convert.ToDouble(_comboSource.EditValue.Item2); 
 58                       }; 59                     60                 } 61                 return _comboSource; 62             } 63         } 64  65         [Display(Name = "SliderEdit", GroupName = "CustomUI")] 66         [CustomUI(CustomUITypes.Slider, nameof(CountSource))] 67         public double Count 68         { 69             get => _count; 70             set 71             { 72                 _count = value; 73                 CountSource.Value = value; 
 74                 RaisePropertyChanged(nameof(Count)); 75             } 76         } 77  78         [Display(Name = "ComboBoxEditItem", GroupName = "CustomUI")] 79         [CustomUI(CustomUITypes.ComboBoxEit, nameof(ComboSource))] 80         public double Value 81         { 82             get => _value; 83             set 84             { 85                 if (_value == value) return; 86                 _value = value; 87                 //ComboSource.Value = value; 88                 RaisePropertyChanged(nameof(Value)); 89             } 90         } 91  92         [Display(Name = "Password", GroupName = "DefaultUI")] 93         public string Password { get; set; } 94  95         [Display(Name = "TextEdit", GroupName = "DefaultUI")] 96         public string Text { get; set; } 97  98         [Display(Name = "Notes", GroupName = "DefaultUI")] 99         public string Notes { get; set; }100 101 102         [Display(Name = "Double", GroupName = "DefaultUI")]103         [DefaultValue(1)]104         public double TestDouble { get; set; }105 106         [Display(Name = "Items", GroupName = "DefaultUI")]107         [DefaultValue(Visibility.Visible)]108         public Visibility TestItems { get; set; }109     }110 111     public static class DynamicallyAssignDataEditorsMetadata112     {113         public static void BuildMetadata(MetadataBuilder<TestPropertyGrid> builder)114         {115             builder.Property(x => x.Password)116                 .PasswordDataType();117 118             builder.Property(x => x.Notes)119                 .MultilineTextDataType();120         }121     }122 }
登入後複製
TestPropertyGrid

#
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()
        {

        }/// <summary>/// Initializes a new instance of the <see cref="SliderUIDataContext"/> class./// </summary>/// <param name="min">The minimum.</param>/// <param name="max">The maximum.</param>/// <param name="value">The value.</param>/// <param name="smallChange">The small change.</param>/// <param name="largeChange">The large change.</param>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;
        }/// <summary>/// Gets or sets the small change./// </summary>/// <value>/// The small change./// </value>public double SmallChange
        {get => _smallChange;set{if (value == _min) return;
                _min = value;
                RaisePropertyChanged(nameof(SmallChange));
            }
        }/// <summary>/// Gets or sets the large change./// </summary>/// <value>/// The large change./// </value>public double LargeChange
        {get => _largeChange;set{if (Value == _largeChange) return;
                _largeChange = value;
                RaisePropertyChanged(nameof(LargeChange));
            }
        }/// <summary>/// Gets or sets the maximum./// </summary>/// <value>/// The maximum./// </value>public double Max
        {get => _max;set{if (value == _max) return;
                _max = value;
                RaisePropertyChanged(nameof(Max));
            }
        }/// <summary>/// Gets or sets the minimum./// </summary>/// <value>/// The minimum./// </value>public double Min
        {get => _min;set{if (value == _min) return;
                _min = value;
                RaisePropertyChanged(nameof(Min));
            }
        }/// <summary>/// Gets or sets the value./// </summary>/// <value>/// The value./// </value>public double Value
        {get => _value;set{if (value == _value) return;
                _value = value;
                RaisePropertyChanged(nameof(Value));
            }
        }
    }
}
登入後複製
TestPropertyGrid
 該類別中用到的其他類別主要有以下幾個,以下幾個類別主要用於資料綁定:
############
using System;using System.Linq;namespace PropertyGridDemo.PropertyGridControl
{public class ComboBoxEditDataContext:PropertyDataContext
    {private Tuple<string, object>[] _itemSource;private Tuple<string, object> _editValue;private int _selectedIndex;/// <summary>/// Initializes a new instance of the <see cref="ComboBoxEditDataContext"/> class./// </summary>/// <param name="itemSource">The item source.</param>/// <param name="editValue">The edit value.</param>public ComboBoxEditDataContext(Tuple<string,object>[] itemSource,Tuple<string,object> editValue)
        {
            _itemSource = itemSource;
            _editValue = _itemSource.FirstOrDefault(x => x?.Item1.ToString() == editValue?.Item1.ToString() && x?.Item2?.ToString() == x?.Item2?.ToString());
        }/// <summary>/// Initializes a new instance of the <see cref="ComboBoxEditDataContext" /> class./// </summary>/// <param name="itemSource">The item source.</param>/// <param name="value">The value.</param>public ComboBoxEditDataContext(Tuple<string, object>[] itemSource, object value)
        {
            _itemSource = itemSource;
            _editValue = _itemSource.FirstOrDefault(x => x?.Item2.ToString() == value.ToString() );
        }public string Name
        {get;set;
        }/// <summary>/// Gets or sets the item source./// </summary>/// <value>/// The item source./// </value>public Tuple<string,object>[] ItemSource
        {get => _itemSource;set{//if (_itemSource == value) return;_itemSource = value;
                RaisePropertyChanged(nameof(ItemSource));
            }
        }/// <summary>/// Gets or sets the edit value./// </summary>/// <value>/// The edit value./// </value>public Tuple<string,object> 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));
            }
        }/// <summary>/// Gets or sets the index of the selected./// </summary>/// <value>/// The index of the selected./// </value>public int SelectedIndex
        {get => _selectedIndex;set{if (_selectedIndex == value || value==-1) return;
                _selectedIndex = value;
                EditValue = ItemSource[value];
                RaisePropertyChanged(nameof(SelectedIndex));
            }
        }
    }
}
登入後複製
登入後複製
######SliderUIDataContext#######
using System;using System.Linq;namespace PropertyGridDemo.PropertyGridControl
{public class ComboBoxEditDataContext:PropertyDataContext
    {private Tuple<string, object>[] _itemSource;private Tuple<string, object> _editValue;private int _selectedIndex;/// <summary>/// Initializes a new instance of the <see cref="ComboBoxEditDataContext"/> class./// </summary>/// <param name="itemSource">The item source.</param>/// <param name="editValue">The edit value.</param>public ComboBoxEditDataContext(Tuple<string,object>[] itemSource,Tuple<string,object> editValue)
        {
            _itemSource = itemSource;
            _editValue = _itemSource.FirstOrDefault(x => x?.Item1.ToString() == editValue?.Item1.ToString() && x?.Item2?.ToString() == x?.Item2?.ToString());
        }/// <summary>/// Initializes a new instance of the <see cref="ComboBoxEditDataContext" /> class./// </summary>/// <param name="itemSource">The item source.</param>/// <param name="value">The value.</param>public ComboBoxEditDataContext(Tuple<string, object>[] itemSource, object value)
        {
            _itemSource = itemSource;
            _editValue = _itemSource.FirstOrDefault(x => x?.Item2.ToString() == value.ToString() );
        }public string Name
        {get;set;
        }/// <summary>/// Gets or sets the item source./// </summary>/// <value>/// The item source./// </value>public Tuple<string,object>[] ItemSource
        {get => _itemSource;set{//if (_itemSource == value) return;_itemSource = value;
                RaisePropertyChanged(nameof(ItemSource));
            }
        }/// <summary>/// Gets or sets the edit value./// </summary>/// <value>/// The edit value./// </value>public Tuple<string,object> 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));
            }
        }/// <summary>/// Gets or sets the index of the selected./// </summary>/// <value>/// The index of the selected./// </value>public int SelectedIndex
        {get => _selectedIndex;set{if (_selectedIndex == value || value==-1) return;
                _selectedIndex = value;
                EditValue = ItemSource[value];
                RaisePropertyChanged(nameof(SelectedIndex));
            }
        }
    }
}
登入後複製
登入後複製
ComboBoxEditDataContext
using System.ComponentModel;namespace PropertyGridDemo.PropertyGridControl
{public class PropertyDataContext:INotifyPropertyChanged
    {/// <summary>/// 在更改属性值时发生。/// </summary>public event PropertyChangedEventHandler PropertyChanged;/// <summary>/// 触发属性变化/// </summary>/// <param name="propertyName"></param>public virtual void RaisePropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
登入後複製
PropertyDataContext
using System;namespace PropertyGridDemo.PropertyGridControl
{internal static class ComboBoxEditItemSource
    {internal static Tuple<string, object>[] TestItemSource = new Tuple<string, object>[] {new Tuple<string, object>("1",1),new Tuple<string, object>("2",2),new Tuple<string, object>("3",3)
        };
    }
}
登入後複製
ComboBoxEditItemSource

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

 1 <Window 2     x:Class="PropertyGridDemo.MainWindow" 3     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5     xmlns:PropertyGridControl="clr-namespace:PropertyGridDemo.PropertyGridControl" 6     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 7     xmlns:local="clr-namespace:PropertyGridDemo" 8     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 9     Title="MainWindow"10     Width="525"11     Height="350"12     WindowState="Maximized"13     mc:Ignorable="d">14     <Grid Margin="10">15         <Grid.ColumnDefinitions>16             <ColumnDefinition Width="259*" />17             <ColumnDefinition Width="259*" />18         </Grid.ColumnDefinitions>19 20         <TextBox21             x:Name="OutputBox"22             Grid.ColumnSpan="1"23             HorizontalScrollBarVisibility="Auto"24             ScrollViewer.CanContentScroll="True" />25         <PropertyGridControl:CustomPropertyGrid x:Name="PropertyGrid" Grid.Column="1" />26     </Grid>27 </Window>
登入後複製
MainWindow

 

运行示意图:

以上就是自定义PropertyGrid控件的实现代码,本人只实现了简单的Slider和ComboBoxEdit控件,实际上可以根据自己的需要仿照以上的方法扩展到其他控件,这个就看需求了。

个人感觉以上方案还是有所欠缺,主要是自定义控件的模板是由代码生成的,如果可以直接从资源文件中读取将会更加方便,不过本人尝试了几次并不能成功的实现数据的绑定,如果大家有什么好的解决方案欢迎在评论区留言,也欢迎大家在评论区进行讨论。

以上内容均为原创,转发请注明出处,谢谢!

 

以上是一個很強大的控制項--PropertyGrid的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板