Silverlight控件的属性值编辑器
简介
这是系列的一部分,在设计时,在实施改变Silverlight 工具包2009年3月发行。 这篇文章讨论了如何增强属性编辑Silverlight中使用属性值编辑器和类型转换器控制的经验。 我将开始与描述中的WPF / Silverlight设计的可扩展框架的整体属性编辑架构,然后使用Silverlight工具包 2009年3月推出 ,以证明它是如何做的例子,并在Silverlight设计时代发展的独特的问题/技巧。
属性编辑架构
可视化编辑对象的属性,是设计师的重要组成部分。 设计师们通常不知道如何使自定义类型的属性(结构,类或接口),更提供了一个很好的编辑用户界面。 控制项开发人员通常需要提供的TypeConverter , PropertyValueEditor ,或两者兼而有之,提供渲染/编辑UI和XAML序列化自定义类型的属性。
设计师可扩展框架定义了三种类型的属性值编辑器内编辑器,扩展编辑器,对话框编辑器,每个类实现:
编辑这些编辑器的UI定义的DataTemplate。 正在编辑的财产暴露在主编的PropertyValue类型的DataContext 。 编辑器UI通常绑定到通过的三个属性编辑PropertyValue : 价值 , StringValue的 ,或者收集相关物业。
PropertyValueEditor
PropertyValueEditor拥有一个单一的内联编辑器中定义的 InlineEditorTemplate属性。 行内编辑器显示属性窗口内。 下面是一个简单的例子InlineEditorTemplate ,使用TextBox来显示和编辑的属性:
x:Key ="TextBoxEditor" > <DataTemplate中 的x:Key =“TextBoxEditor”> Text ="{Binding Path=Value}" /> <TextBox的Text =“{绑定路径=值}”/> > </ DataTemplate中 >
ExtendedPropertyValueEditor
x:Key ="inlineEditor" > <DataTemplate中 的x:Key =“inlineEditor”> Content ="..." Command ="{x:Static PropertyEditing:PropertyValueEditorCommands.ShowDialogEditor}" /> << 按钮 内容 ="..." 命令=“{X:静态PropertyEditing:PropertyValueEditorCommands.ShowDialogEditor}”/ > > </ DataTemplate中 > x:Name ="slider" Value ="{Binding Path=Value}" /> < 滑块 X:名称 =“滑块” 值 =“{绑定路径=值}”/> > </ DataTemplate中 >
DialogPropertyValueEditor
DialogPropertyValueEditor也有两个编辑:继承PropertyValueEditor内编辑器,和一个额外的对话框编辑器中定义的 DialogEditorTemplate属性。 对话框编辑器通常是通过内联编辑器PropertyValueEditorCommands 。弹出ShowDialogEditor命令。 下面是一个简单的例子:
x:Key ="inlineEditor" > < Button Content ="..." Command ="{x:Static <DataTemplate中 的x:Key =“inlineEditor”> < 按钮 内容 ="..." 命令 =“{X:静态 ="Center" HorizontalAlignment ="Right" Margin ="0,0,4,4" /> < TextBox Text ="{Binding 名称:“VerticalAlignment =”中心“HorizontalAlignment =”右“ 保证金 =”0,0,4,4“/> <TextBox 的Text =”{绑定
实现自定义的属性编辑器
为了实现一个Silverlight控件自定义属性编辑器:
- 实现自定义的属性编辑器类
- 继承PropertyValueEditor,ExtendedPropertyValueEditor,或DialogPropertyValueEditor
- 设置它的编辑模板(S): InlineEditorTemplate , ExtendedEditorTemplate ,和/或DialogEditorTemplate ;
- 与Silverlight控件的属性通过AddCustomAttributes调用自定义属性编辑器,类似关联
- 正确实施的属性值编辑器必须满足以下要求:
- 属性值编辑器的设计必须使内联的编辑器和扩展编辑器部件可以单独使用。
- 属性值编辑器不得存储状态。 属性值编辑器是无状态的,可能会被缓存由一台主机实现,并可以重复使用跨多个属性值。
- 属性值编辑器不能假设只有一个值编辑器的一部分(查看/直列/扩展)控制在一个给定的的时间。 例如,一个对话框,可视图的一部分,内联的一部分,同时积极扩展的UI部分。
- 属性值编辑器的一部分实施了控制,绝不能存储的状态。 实施了控制值编辑器的一部分,不应该假设,它只会被绑定到一个属性值。 控制,可能会被回收改变不同的属性值。 如果数据模型是更新缓存的任何信息应该被刷新。
- 主机或它的父控件属性值编辑器的一部分实施了控制,绝不能做出任何假设。 应使用唯一的通信机制PropertyValue数据模型的DataContext的方式,和标准的命令集。
同时引用WPF和Silverlight的大会
一个设计大会是由Visual Studio或混合装载一个.NET / WPF组件,但它通常需要参考的Silverlight组件(至少Silverlight控制组件,它提供了设计时功能)。 这可以建立参考设计装配项目的模糊性:有时需要参考在WPF和Silverlight相同的完全限定的类型,说在两个Silverlight的WPF和System.Windows.dll PresentationFramework.dll System.Windows.FrameworkElement。 为了避免混淆的Visual Studio,您可以使用extern别名来区分WPF和Silverlight引用。
例如,看到下面的截图Controls.DataVisualization.Toolkit.Design在Silverlight 3工具包项目2009年3月发布 :
- 项目引用PresentationFramework和System.Windows,但System.Windows下Silverlight的别名,而不是默认的全球的别名。 在Silverlight的别名System.Windows参考坚持csproj文件如下。
Include ="System.Windows, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, processorArchitecture=MSIL" > <=“System.Windows,版本= 2.0.5.0,文化=中性公钥= 7cec85d7bea7798e processorArchitecture = MSIL的” 参考 包括 > > False </ SpecificVersion > <SpecificVersion> </ SpecificVersion> > ..\Binaries\System.Windows.dll </ HintPath > <HintPath> .. \ Binaries文件\ System.Windows.dll </ HintPath> > False </ Private > < 私人 > FALSE </> > Silverlight </ Aliases > < 别名 >的Silverlight </ 别名 > > </ 参考 >
- 在源代码中,我们添加
extern别名的Silverlight; 西南偏南= Silverlight的:System.Windows;
和参考Silverlight的FrameworkElement的通过西南偏南:FrameworkElement的。
TextBoxEditor
在Controls.DataVisualization.Toolkit.Design项目的内联编辑器,用于显示和编辑对象的类型名称属性TextBoxEditor [区|酒吧|泡泡|列|线|馅饼|分散系列和图表控件,如下所示:
填写标题字段属性“窗口右侧文本自动显示在XAML和设计在中间的意见。
TextBoxEditor实施遵循了之前的步骤:
- TextBoxEditor是一个子类的PropertyValueEditor。 它集InlineEditorTemplate在其默认构造。 这里,我使用的XAML代码,而不是兴建的 DataTemplate ,因为不知何故,我不能得到XAML建立,并在XAML中的一切都可以改写在C#反正。
- 这是与ChartMetadata.cs Chart.Title( * Metadata.cs文件的更多信息,请参阅Silverlight工具包的设计时功能的实现)
TextBoxEditor.cs:
/ /版权所有(C)Microsoft Corporation版权所有。 / /这个源是受微软公共许可证(MS - PL)。 / /详细信息,请参阅http://go.microsoft.com/fwlink/?LinkID=131993。 / /保留所有其他权利。 使用系统; 使用 Microsoft.Windows.Design.PropertyEditing; 使用 System.Windows; 使用 System.Windows.Data; 命名空间 System.Windows.Controls.DataVisualization.Design { / / / <summary> / / /简单的TextBox的行内编辑器。 / / / </摘要> 公共部分类 TextBoxEditor:PropertyValueEditor { / / / <summary> / / /保存从PropertyValueEditor的构造函数的原型 。 / / / </摘要> / / / <param name="inlineEditorTemplate">内编辑器模板。</ PARAM> 公共 TextBoxEditor(DataTemplate的inlineEditorTemplate) 基地 :(inlineEditorTemplate) {} / / / <summary> / / /默认的构造方法建立默认的TextBox在线编辑器模板。 / / / </摘要> 公共 TextBoxEditor() { (TextBox)); FrameworkElementFactory的TextBox = 新FrameworkElementFactory(typeof运算 (文本框)); 绑定绑定新的绑定(); ); binding.Path = 新 PropertyPath的(“值”); binding.Mode = BindingMode.TwoWay; textBox.SetBinding(TextBox.TextProperty,绑定); DataTemplate的DT = 新的DataTemplate(); dt.VisualTree =文本框; InlineEditorTemplate = DT; } } }
CultureInfoEditor
我的同事的RJ写内联编辑器CultureInfoEditor TimePicker.Culture属性,因为默认情况下,编辑在Blend中的CultureInfo经验,会导致无效的XAML。 下面的截图显示CultureInfoEditor使用一个ComboBox显示所有的CultureInfo,并产生正确的的XAML。
CultureInfoEditor比TextBoxEditor更复杂的例子,真正体现出的基本属性是如何通过DataContext属性编辑器相关。
CultureInfoEditor.cs:
/ /版权所有(C)微软公司。/ /此源是受微软公共许可协议(MS - PL)/ / /详情请参阅http://go.microsoft.com/fwlink/?LinkID=131993。 /所有其他的权利 CultureInfoEditor : PropertyValueEditor { /// <summary> /// The ComboBox being used to edit the value. /// </summary> private ComboBox _owner; /// <summary> /// Preserve the constructor prototype from PropertyValueEditor. /// </summary> /// <param name="inlineEditorTemplate">Inline editor template.</param> public CultureInfoEditor(DataTemplate inlineEditorTemplate) : base (inlineEditorTemplate) { } /// <summary> /// Default constructor builds a ComboBox inline editor template. /// </summary> public CultureInfoEditor() { // not using databinding here because Silverlight does not support // the WPF CultureConverter that is used by Blend. FrameworkElementFactory comboBox = new FrameworkElementFactory( typeof (ComboBox)); comboBox.AddHandler( ComboBox.LoadedEvent, new RoutedEventHandler( (sender, e) => { _owner = (ComboBox) sender; _owner.SelectionChanged += EditorSelectionChanged; INotifyPropertyChanged data = _owner.DataContext as INotifyPropertyChanged; if (data != null ) { data.PropertyChanged += DatacontextPropertyChanged; } _owner.DataContextChanged += CultureDatacontextChanged; })); comboBox.SetValue(ComboBox.IsEditableProperty, false ); comboBox.SetValue(ComboBox.DisplayMemberPathProperty, "DisplayName" ); comboBox.SetValue(ComboBox.ItemsSourceProperty, CultureInfo.GetCultures(CultureTypes.SpecificCultures)); DataTemplate dt = new DataTemplate(); dt.VisualTree = comboBox; InlineEditorTemplate = dt; } /// <summary> /// Handles the SelectionChanged event of the owner control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="System.Windows.Controls.SelectionChangedEventArgs"/> /// instance containing the event data.</param> private void EditorSelectionChanged( object sender, SelectionChangedEventArgs e) { // serialize with name. object DataContext = _owner.DataContext; DataContext .GetType() .GetProperty( "Value" , BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty) .SetValue(DataContext, ((CultureInfo)_owner.SelectedItem).Name, new object [] { }); } /// <summary> /// Handles the PropertyChanged event of the context object. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="System.ComponentModel.PropertyChangedEventArgs"/> instance containing the event data.</param> private void DatacontextPropertyChanged( object sender, PropertyChangedEventArgs e) { // deserialize from name. if (e.PropertyName == "Value" ) { object value = sender .GetType() .GetProperty( "Value" , BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty) .GetValue(sender, new object [] { }); if ( value != null ) { if ( value is string ) { CultureInfo setCulture = new CultureInfo( value .ToString()); _owner.SelectedItem = setCulture; } } } } /// <summary> /// Called when the context is changed. /// </summary> /// <param name="sender">The sender.</param> /// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param> private void CultureDatacontextChanged( object sender, DependencyPropertyChangedEventArgs e) { INotifyPropertyChanged old = e.OldValue as INotifyPropertyChanged; if (old != null ) { old.PropertyChanged -= DatacontextPropertyChanged; } INotifyPropertyChanged newDataContext = e.NewValue as INotifyPropertyChanged; if (newDataContext != null ) { newDataContext.PropertyChanged += DatacontextPropertyChanged; } } } } {/ / / <summary> / / /编辑器的CultureInfo / / / </摘要> / / / <remarks>目前不支持绑定XAML编辑器</备注 >公共类CultureInfoEditor。PropertyValueEditor {/ / / <summary> / / / ComboBox中被用来编辑该值/ / / </摘要> 私人的ComboBox _owner;,/ / / <summary> / / /从PropertyValueEditor保存的构造函数的原型/ / / </摘要 > / / / <param name="inlineEditorTemplate">内编辑器模板</ PARAM> 公共 CultureInfoEditor(DataTemplate中inlineEditorTemplate): 基地 (inlineEditorTemplate){} / / / <summary> / / /默认构造函数建立一个ComboBox内编辑器模板 。 = 新FrameworkElementFactory(typeof运算 (组合框)); / / / </摘要> 公共 CultureInfoEditor(){/ /不使用数据绑定在这里,因为Silverlight不支持/ / WPF CultureConverter,是由Blend FrameworkElementFactory组合框。comboBox.AddHandler( ComboBox.LoadedEvent, 新 RoutedEventHandler((发件人,E)=> {_owner =(组合框)发件人; _owner.SelectionChanged + = EditorSelectionChanged; INotifyPropertyChanged的数据= _owner.DataContext INotifyPropertyChanged的!(数据= NULL){data.PropertyChanged + = DatacontextPropertyChanged;} _owner.DataContextChanged + = CultureDatacontextChanged;})); comboBox.SetValue(ComboBox.IsEditableProperty 假 ); comboBox.SetValue(ComboBox.DisplayMemberPathProperty,“显示名称”); comboBox.SetValue(ComboBox.ItemsSourceProperty,CultureInfo.GetCultures (CultureTypes.SpecificCultures)); DataTemplate的DT = 新的DataTemplate(); dt.VisualTree =组合框; InlineEditorTemplate = DT;} / / / <summary> / / /处理的所有者控制SelectionChanged事件/ / / </摘要> / / / <param name="sender">事件。</ PARAM> / / / <param name="e"> <see源cref="System.Windows.Controls.SelectionChangedEventArgs"/> / / /实例,其中包含事件数据。</ PARAM> 私人无效 EditorSelectionChanged( 对象发件人,SelectionChangedEventArgs发送){/ /名称序列化 对象的DataContext = _owner.DataContext;的DataContext的GetType()的getProperty(“价值”的BindingFlags。 。公开| BindingFlags.Instance | BindingFlags.GetProperty)的SetValue(DataContext的,((的CultureInfo)_owner.SelectedItem)名称, 新的对象 [] {});} / / / <summary> / / /处理PropertyChanged事件上下文对象。/ / / </摘要> / / / <param name="sender">事件源。</ PARAM> / / / <param name="e"> <CREF =“系统。 ComponentModel.PropertyChangedEventArgs“/>实例包含事件数据。</ PARAM> 私人无效 DatacontextPropertyChanged( 对象发件人,PropertyChangedEventArgs发送){/ /反序列化的名称。(e.PropertyName ==”值“){ 对象的值 =发件人。的GetType()的getProperty(“价值”,BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty)的GetValue(发件人, 新的对象 [] {});( 值= NULL){ 如果 ( 值是字符串 ){ CultureInfo的setCulture = 新的CultureInfo(值的ToString()); _owner.SelectedItem = setCulture;}}}} / / / <summary> / / /上下文改变时调用/ / / </摘要> / / / <参数:name =“发件人”> </ PARAM> / / / <param name="e"> <see cref="System.Windows.DependencyPropertyChangedEventArgs"/>实例包含事件数据。</ PARAM>发件人 私人无效 CultureDatacontextChanged( 对象发件人,DependencyPropertyChangedEventArgs发送){INotifyPropertyChanged的老= e.OldValue INotifyPropertyChanged的;(旧= NULL){old.PropertyChanged -= DatacontextPropertyChanged;} INotifyPropertyChanged的newDataContext = e.NewValue INotifyPropertyChanged的;!(newDataContext = NULL ){newDataContext.PropertyChanged + = DatacontextPropertyChanged;}}
ExpandableObjectConverter
除了自定义属性值编辑器,在开始讨论,有时你可以使用适当的类型转换器提供良好的编辑体验和XAML序列化。 一个例子是ColumnSeries.DependentRangeAxis:IRangeAxis类型,混合不知道如何编辑,所以它显示DependentRangeAxis为只读属性面板只。 关联ExpandableObjectConverter ColumnSeries.DependentRangeAxis:
b.AddCustomAttributes( Extensions.GetMemberName <ColumnSeries>(X => x.DependentRangeAxis) (ExpandableObjectConverter))); 新TypeConverterAttribute(typeof运算 (ExpandableObjectConverter))); b.AddCustomAttributes( Extensions.GetMemberName <ColumnSeries>(X => x.IndependentAxis) (ExpandableObjectConverter))); 新TypeConverterAttribute(typeof运算 (ExpandableObjectConverter)));
混合显示一个新的按钮,这个属性在属性面板,点击后弹出选择对象“对话框,属性的类型IRangeAxis过滤:
结论
Blend和Silverlight的让设计师创造惊人的用户界面,直接对实时控制,所以它是非常重要的,控制开发商拿设计师的经验作为整体控制设计和实施的一部分。 在一个自定义的属性编辑器,提供了良好的编辑UI,并产生正确的XAML是一个设计师的经验的重要组成部分。 希望这篇文章可以帮助您了解如何创建自定义的属性编辑器。 谢谢!








最近的评论