ホームページ  >  記事  >  バックエンド開発  >  非常に強力なコントロール PropertyGrid

非常に強力なコントロール PropertyGrid

零下一度
零下一度オリジナル
2017-06-24 09:49:136028ブラウズ

PropertyGrid は非常に強力なコントロールです。このコントロールをプロパティ設定パネルとして使用する利点の 1 つは、PropertyGrid が UI のプレゼンテーションではなく、コードにのみ注目する必要があることです。デフォルトでは変数タイプ。しかし、これは問題も引き起こします。つまり、主に、たとえば、int 変数を設定するために Slider コントロールを使用する必要がある場合、ニーズに応じてコントロールを選択できないため、コントロールの使用はそれほど柔軟ではありません。 PropertyGrid のデフォルトは次のとおりです。テンプレート セレクターはサポートされていません。基本的に IWindowFromService インターフェイスを使用した WinForm の実装を紹介する多くの情報をインターネット上で見つけましたが、WPF に適した適切なデモが見つかりませんでした。その後、DEVExpress の公式デモを参照してデモを作成しました。 WPF および DEV 16.2 では、PropertyGrid デモは基本的に上記の機能を実装します。

これを実現するには、この記事の中心となるコードでもある 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>
ResourceDiction ary

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

このクラスで使用されるその他のクラスには主に次のものが含まれており、次のクラスは主にデータ バインディングに使用されます:

すごい
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 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。