【翻译】SILVERLIGHT设计时扩展(注:内容超长,请用IE浏览)
嗨伙计们,
只要有人谈到开发者与设计师在 Silverlight/WPF上协同工作时,他们就会谈论“设计,开发工作流程”这个
问题。即使您是您自己的设计师,这工作也始终是永远存在于当你在“设计师”和“开发”之间切换“帽子”的过程中。
我是一个使用工具创建用户界面的支持者。 我的生活让我不能理解为什么有人会选择非产能(non-productive)
和手写XAML的事情。
你能找出的一个情况就是当你使用(Expression Blend & Visual Studio WPF/Silverlight Designer)这类工
具进行工作时,如果使用正确,这些工具会对提高生产力起到巨大的推动作用。然而,这篇帖子不是关于如何使用
这类工具,而是关于如何帮助那些使用您的控件作为工具进行设计的人。本文是关于开发者着手去让设计师有更容
易的(设计)体验并减少摩擦。
控件提供商和开发者通常都想给自己的控件以更好的体验。然而,在这个问题上其缺乏大量的信息。我决定用
本文纠正这种情况。
本文也与那些在项目中有设计师一起工作的开发者有关。我建立的解决方案可在这里下载,SilverlightControls.zip
介绍:
首先,我们会考虑在设计时的Assemblies工作。
考虑下面这个类:
{
public string MyStringProperty { get; set; }
}
现在,考虑下面这个设计时属性的类:
public class myControl : Control
{
[Description("I am a property")]
public string MyStringProperty { get; set; }
}
在设计时assemblies 工作的方式就是将设计时属性与实际的类进行分离。之后我们的类会是这个样子:
{
public string MyStringProperty { get; set; }
}
并且在我们的设计时组装过程时,代码相当于:
builder.AddCustomAttributes(new DescriptionAttribute("I am a control 2")));
AddCallback(typeof(myControl), builder =>
builder.AddCustomAttributes("MyStringProperty", new DescriptionAttribute("I am a property")));
在没有研究太多API的情况下,可以看到第一行会显示“myControl has the following DescriptionAttribute”,
第二行显示:“myControl.MyStringProperty has this DescriptionAttribute”.
我们从运行时代码中分离出设计时代码. 下面让我们看一下在BLEND中,它的样子:
这一做法有哪些优势?
2.基于工具修改设计时属性。这种做法允许支持不同的设计时属性,而这些属性基于它们运行的工具。
3.设计时变更无须重新编译运行时组件。
4.不是运行时组装的author可以添加设计时属性。
5.高级的设计时支持,并不需要我们使用GUIDs注册Visual Studio软件包。
参考架构
这里有一些步骤. 从本质上讲,我们要建立以下结构:
一点都不乱(译者注:我看有点乱,呵呵),是吧?简单地说,这仅仅是参考模型。
我们将创建3个新项目。
*. VisualStudio.design.dll -将包含设计时的功能,仅用于Visual Studio。
*. Expression.design.dll -将包含设计时的功能,仅用于Expression blend。
这种命名约定是强制性的。
第一步是增加项目引用,我们会在该项目中添加设计时支持用于设计时组件:
添加对共享设计时dll的引用:
并添加Blend design-time 引用:
步骤:
1. 添加一个Silverlight 类库,该类库会包含我们的控件. 我们将它命名为:SilverlightControls.
2. 添回一个myControl 类.
{
public string MyStringProperty
{
get { return GetValue(MyStringPropertyProperty) as string; }
set { SetValue(MyStringPropertyProperty, value); }
}
public static readonly DependencyProperty MyStringPropertyProperty =
DependencyProperty.Register("MyStringProperty",typeof(string), typeof(myControl), null);
}
3. 创建共享运行时DLL. 因为控件被命名为“SilverlightControls” ,所以这里命名为“SilverlightControls.Design”.
这里选择类型为“WPF Custom Control library” 因为稍后会使用一些WPF 特性.如果喜欢,我们可以手工添加引用到普通类库项目中。
4. 在“SilverlightControls.Design” 项目中添加对“SilverlightControls” 项目的引用, 以及Microsoft design time 组件和
Silverlight System.Windows.dll.
(Silverlight 2 引用路径– 默认位于 c:"Program Files"Microsoft SDKs"Silverlight"v2.0"Reference Assemblies)
这是我们引用的组件:
5. 创建visual studio 设计时DLL.
因为要添加的设计时用于“SilverlightControls” 所以这里命名为:“SilverlightControls.VisualStudio.Design”.
6. 在项目“SilverlightControls.VisualStudio.Design” 中添加对“SilverlightControls”的引用, 以及
Microsoft design time assemblies 和 Silverlight System.Windows.dll.
这里我们添加的引用:
7. 创建expression blend 设计时 DLL.
因为要添加的设计时用于“SilverlightControls” 所以这里命名为“SilverlightControls.Expression.Design”.
8. 在项目“SilverlightControls.Expression.Design” 中添加对“SilverlightControls” 的引用,Microsoft
design time assemblies 和 Blend specific dlls。
这里我们添加的引用:
9. 我们需要在三个运行时组件项目中分别添加一个类,该类实现了IReigsterMetadata 接口.
我在这三个项目中使用下面模版.
{
private static AttributeTable _customAttributes;
private static bool _initialized;
public void Register()
{
if (!_initialized)
{
MetadataStore.AddAttributeTable(CustomAttributes);
_initialized = true;
}
}
public static AttributeTable CustomAttributes
{
get
{
if (_customAttributes == null)
{
_customAttributes = new CustomMetadataBuilder().CreateTable();
}
return _customAttributes;
}
}
private class CustomMetadataBuilder : AttributeTableBuilder
{
public DeveloperMetadataBuilder()
{
// TODO: Add Design time code here!
}
private void AddTypeAttributes(Type type, params Attribute[] attribs)
{
base.AddCallback(type, builder => builder.AddCustomAttributes(attribs));
}
private void AddMemberAttributes(Type type, string memberName, params Attribute[] attribs)
{
base.AddCallback(type, builder => builder.AddCustomAttributes(memberName, attribs));
}
}
}
我不想深入研究这个类做了什么,以及IRegisterMetadata 和 AttributeTableBuilder 是什么, 您可以到
MSDN 上去查找. 我只想说,它们是extensibility framework 中的类,通过它们,我们可以对我们的类添加设
计时支持。并且,我也不打算深入分析我的 template 做了什么. 起码它确保 Metadata 仅被创建一次,并且提
供了简单的访问方法,这些方法我们会在本DEMO中到处使用。
好,这就是我们当前的项目结构:
注:我们在每个项目中都已有了一个metadata 类.
10. 安装设计时文件拷贝。
设计时DLL文件须与运行时DLL文件放在相同的目录下.
我喜欢自动完成相关的*design.dll 文件拷贝. 你可以手工完成这一操作。
我使用的自动方式是添加一条 post-build action 到每个设计时项目中.
右击我们的项目文件 –> “属性” –> “生成事件”. 粘帖下面内容到Post Build Events:
在所有的三个设计时项目中重复这一步骤.
创建我们的测试项目
1. 我们使用BLEND创建一个新的项目来使用我们的DLL. 我们会使用该项目来预览我们的设计时改进。
2. 添加对“SilverlightControls.dll”的引用.
这时发生了什么?
我们有了两个设计时dll约束. 因为这两个约束会被工具自动加载到tools:
Design time DLLs 文件与 runtime DLL在一起.
Design time DLLs 遵守命名协定.
<RuntimeName>.Design.dll – 共享设计时
<RuntimeName>.Expression.Design.dll – 用于expression blend 设计时
<RuntimeName?.VisualStudio.Design.dll – 用于Visual studio wpf/silverlight 设计器
现在我们有了这个基本架构,接下来就开始用一下吧.
(注:原文作者在这里好像就做了一个章节,下面是后续的文章内容:属性讲解)
DescriptionAttribute (Shared)
Description 是一个让我们在设计时工具中显示类似智能说明的方法. 该属性用于在类和属性之间进行工作。
当我们说某个属性是“Shared” 时,它意味着工作在两个工具之间并且须放在共享设计时 dll中.
尽管当前 Visual studio 有只读的设计时界面, 一旦其获得一个可以编辑的设计界面,这些都会在两个工具间被支持.
那就让我们在SilverlightControls.Design.MetadataRegistration类型中DescriptionAttribute.
{
AddTypeAttributes(typeof(myControl),
new DescriptionAttribute("I am a control"));
AddMemberAttributes(typeof(myControl),"MyStringProperty",
new DescriptionAttribute("I am a property"));
}
现在编译我们的应用并在Expression Blend看一下这些描述。
DisplayNameAttribute (shared)
显示名称属性用于显示类型成员的(friendlier)名称.
AddMemberAttributes(typeof(myControl),"MyStringProperty",
new DescriptionAttribute("I am a property"),
new DisplayNameAttribute("My String Property"));
下面是其在 Blend中的显示:
CategoryAttribute (shared)
每个属性都有一个默认分类. Blend 为我们的控件定义如下分类:
默认情况下,我们的属性添加到了“Miscellaneous” 分类. 如果想重新定义它,我们可让它在别处。
我们可能想让我们的属性添加到已有的分类中,比如“Common Properties”.
new DescriptionAttribute("I am a property"),
new DisplayNameAttribute("My String Property"),
new CategoryAttribute("Common Properties"));
在Blend中,我们看到它被移动到了那个分类下:
我们可能想去创建我们自己在分类,该分类我们称之为“My Category”.
new DescriptionAttribute("I am a property"),
new DisplayNameAttribute("My String Property"),
new CategoryAttribute("My Category"));
Blend 甚至可以在一个相同的自定义分类中进行属性分组(group properties).
让我们在控件中添加一个新的Integer 类型属性:
{
public string MyStringProperty
{
get { return GetValue(MyStringPropertyProperty) as string; }
set { SetValue(MyStringPropertyProperty, value); }
}
public static readonly DependencyProperty MyStringPropertyProperty =
DependencyProperty.Register("MyStringProperty",typeof(string), typeof(myControl), null);
public int MyIntProperty
{
get { return (int)GetValue(MyIntPropertyProperty) ; }
set { SetValue(MyIntPropertyProperty, value); }
}
public static readonly DependencyProperty MyIntPropertyProperty =
DependencyProperty.Register("MyIntProperty", typeof(int), typeof(myControl), null);
}
我们将它添加到我们自定义的分类中.
new DescriptionAttribute("I am a property"),
new DisplayNameAttribute("My String Property"),
new CategoryAttribute("My Category"));
AddMemberAttributes(typeof(myControl), "MyIntProperty",
new CategoryAttribute("My Category"));
我们会看到在‘My Category’中有两个属性:
BrowsableAttribute (shared)
Browsable 属性允许我们隐藏一些属性,这些属发现在Blend’的数据面板(Data pane)或Visual
Studio的属性窗口中不再有效.
new DescriptionAttribute("I am a property"),
new DisplayNameAttribute("My String Property"),
new CategoryAttribute("My Category"));
AddMemberAttributes(typeof(myControl), "MyIntProperty",
new CategoryAttribute("My Category"),
BrowsableAttribute.No);
当我们在 Blend运行当前应用时,会看到在Data Pane中不在有该属性了:
我们能够使用 browsable 属性隐藏一些继承的属性以及我们自定义的属性.
EditorBrowsableAttribute (Blend)
我仅在Blend 设计时项目中标记了这个属性, 但这是出于我对Visual Studio Silverlight 设计器的猜测.
这可能在VS的一些流行特征中支持, 但我建议在使用之前先考虑它。Editor Browsable 高级状态可以让你在
Blend 中的一个分类下隐藏一些属性,除非用户喜欢看到这些。基本上,隐藏一下较少使用的属性可以让分类
显示更加清楚。
让我们打开expression blend metadata 项目中的元数据文件并添加下面设计时:
new EditorBrowsableAttribute(EditorBrowsableState.Advanced));
这是Blend 显示的分类:
我们会在该分类上看到一个小的“隐藏”箭头:
如果点击它, 会展开并显示该分类下的所有高级属性:
如果用户离开控件然后在选中它时,该分类显示将再次关闭:
那我们在这里假设直到你需要时我们在显示它.
在Silverlight Framework 属性里在什么地方应用该属性呢? 很多地方.
下面是在Silverlight的“Layout” 分类中:
然后我点击它:
我们明白了为什么要在同一分类下避免显示太多的属性.
TypeConverterAttribute (Shared)
指定用作此属性所绑定到的对象的转换器的类型。
起初, 它被用在从UI到后台模型的值转换操作. 它在Blend 2 SP1 在现在还无法使用.
如果能使用就好了, 因为它有一些不错的东西.
在Blend TypeConverters能做的一件事是支持标准值,我们会在操作中看到.
在我们的类似对象“MyObject”添加另一个属性:
{
public string MyStringProperty
{
…
}
public int MyIntProperty
{
…
}
public object MyObjectProperty
{
get { return (object)GetValue(MyObjectPropertyProperty); }
set { SetValue(MyObjectPropertyProperty, value); }
}
public static readonly DependencyProperty MyObjectPropertyProperty =
DependencyProperty.Register("MyObjectProperty", typeof(object), typeof(myControl), null);
}
这是该属性的默认设计时:
我们通过创建一个简单的TypeConverter开始:
{
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
{
return true;
}
public override TypeConverter.StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
{
return new StandardValuesCollection(new string[] { "Hello" ,"World", "foo", "bar"});
}
}
该类型converter 的工作就是对任何使用该converter的属性写入相应的(可能)值(以代码方式).
下面在共享设计时metadata中,我们加入了对该 TypeConverter的引用:
new CategoryAttribute("My Category"),
new TypeConverterAttribute(typeof(myTypeConverter)));
然后我们在 Blend应用它:
我们得到了一系列可供选择的值(以代码方式).
同样,我们可以使用内置式的TypeConverters, 比如 Boolean Converter:
new CategoryAttribute("My Category"),
new TypeConverterAttribute(typeof(BooleanConverter)));
这是它在 Blend的效果:
某些TypeConverters 甚至提供了可视工具化的提示,用来设置当前属性.
下面就是一个不错的例子,ExpandleTypeConverter:
new CategoryAttribute("My Category"),
new TypeConverterAttribute(typeof(ExpandableObjectConverter)));
这是它在 Blend的效果:
然后点击“new” 按钮会弹出一个“对象”对话框:
PropertyOrderAttribute (Shared)
Property order 属性可以让我们定义已存在的属性在某分类下的排序位置.
我们通过定义三个属性来加以说明, 为此我打算将MyIntProperty挪到 advanced 区域外. (在blend 设计时的元数据文件)
new EditorBrowsableAttribute(EditorBrowsableState.Advanced));
在取消 MyIntProperty隐藏之后, 下面是我们默认的属性排序:
它是基于字母排序方式的.
首先“MyIntProperty”, 第二“MyObjectProperty” ,然后第三 “My String Property”.
现在我们想让 MyStringProperty 排在第一的位置.
new DescriptionAttribute("I am a property"),
new DisplayNameAttribute("My String Property"),
new CategoryAttribute("My Category"),
new PropertyOrderAttribute(PropertyOrder.Early));
这是它在 Blend的效果:
我有点想看一下这个PropertyOrder 类了. 让我们仔细看一下它的 static 成员.
好的, 现在我想让MyIntProperty 显示在最后.
new CategoryAttribute("My Category"),
new PropertyOrderAttribute(PropertyOrder.Late));
我们看到在Blend中该属性目前是最后一项了:
那如果我们将 MyObjectProperty 与“My String Property” 同时定义在PropertyOrder.Early?
new CategoryAttribute("My Category"),
new TypeConverterAttribute(typeof(ExpandableObjectConverter)),
new PropertyOrderAttribute(PropertyOrder.Early));
它们会首先会 property order 排序,然后是基于字母排序:
因为“MyObjectProperty” 与“My String Property” 都有相同的property order, 它们会在内部通过字母进行排序.
现在,基于练习的原因, 我会让当前的Property Ordering 相同并在内部对这些属性进行手工排序.
我们尝试将“My String Property” 移到“MyObjectProperty”之前.
new CategoryAttribute("My Category"),
new TypeConverterAttribute(typeof(ExpandableObjectConverter)),
new PropertyOrderAttribute(PropertyOrder.CreateAfter(PropertyOrder.Early)));
然后我们会看到MyObjectProperty 排到了“My String property”之后:
注意:PropertyOrder.CreateBefore/After 方法会返回一个PropertyOrder, 我们可以依据我们的喜好手工进行排序。
(注:作者在此处又结束了一篇,下面是接下来的内容)
NumberRangeAttribute, NumberIncrementAttribute, NumberFormatAttribute (Blend)
在Expression DLLs中这些属性很重要, 因此它们被用在了 Blend(当然项目)中.
让我们看一个我们在什么属性上声明使用了它们: Opacity
首先我们注意在此处有一个比例数值. Opacity 被显示为百分比格式.
接着我们看到有一个标识符‘%’跟在该数值后. 现在我们通过鼠标滚轮加/减当前数值.
如果我们 drag 鼠标并按 SHIFT 键会看到递增单位被加的更大:
或drag 鼠标并按CTRL + SHIFT 键会看到递增单位被加的更小:
(通过上面的演示)我们能看出两件事:
1. 有三种 increments/decrements 方式– Small, Large 和 normal
2. 存在0-100的数值范围
这两种情况我们之前都看到了,其就是基于这些属性实现的.
让我们看一下这些属性的构造方法:
NumberRangeAttribute 属性可以让我们指定最小 & 最大值的范围.
NumberIncrementAttribute 属性可以让我们指定small, default 和large 递增类型.
NumberFormatAttribute 属性可以让我们指写显示内容的格式, 数字精度,显示比率等.
在我们的blend metadata 文件中, 为MyIntProperty 添加下列属性:
将数值范围限制在1-100之间, 指定increments 为0.5, 1 和 5, 显示比率为 x10 以及格式为 “X%”.
我们将范围限制在1-100:
new NumberRangesAttribute(null, 1, 100, null, null));
分别添加 0.5, 1 和 5 increments 用于small, default 和 large increments:
new NumberRangesAttribute(null, 1, 100, null, null),
new NumberIncrementsAttribute(0.5, 1, 5));
最后添加‘X%’格式用于显示10的比率.
new NumberRangesAttribute(null, 1, 100, null, null),
new NumberIncrementsAttribute(0.5, 1, 5),
new NumberFormatAttribute("0'%'", null, 10));
运行这个例子并采用普通 dragging :
然后drag 并按下SHIFT 键:
这是MyIntProperty实际初始值:
我们得到了我们想要的: 取值范围在0-100, 显示比率, 格式以及increments.
(注:原文作者在此又结束了一章)
ToolboxBrowsableAttribute (Shared)
我们将几个控件编译在一起然后在Visual studio Silverlight 工具栏中添加它们或放在Blend库中.
如果我们打算隐藏这些控件中的一个时, 我们可以使用ToolboxBrowsableAttribute . 一个不错的
例子就是ComboBox 是可见的,但ComboBoxItem 被隐藏, 日期可见但DayButton 不可见等等.
在Visual Studio 2008 SP1, Blend 2 SP1这两个工具中,该属性仅是设计时属性.
下面我们创建另一个控件.
{
}
在Blend 里,我们会在asset gallery中看到一个新的控件:
在Visual studio 里,我们打开 “Choose Items” 对话框, 找到“SIlverlightControls.dll” 并点击.
现在,我们着手在这些对话框中隐藏myOtherControl。 我们在共享设计时元数据项目中添加 ToolboxBrowsableAttribute。
new ToolboxBrowsableAttribute(false));
之后编辑并重启 blend, 我们看到在Blend 的Asset Gallery中不再出现该控件了:
然后在Visual studio 的“Choose Items” 对话框中也没再显示myOtherControl:
Inline Editors (Shared)
Editors 是一个在Visual Studio 属性窗口和 Blend Data Pane中的定制元素.
下面是一些已知的editors 例子:
我们在custom project 项目中定义我们的editors 以避免Silverlight dlls 的二义性引用(ambiguous references).
Naming convention and the very existence of this project are optional.
我们添加一些必要的设计时引用.
也要确保在 “SilverlightControls.Design.dll” 中对“SilverlightControls.Design.Editors.dll”的引用.
我们着手在Editors项目中添加一个ResourceDictionary,将其命名为“EditorDictionary”.
在EditorResources.xaml 里添加如下的DataTemplate:
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DataTemplate x:Key="ColorsComboBox">
<ComboBox Text="{Binding StringValue}" IsEditable="True">
<ComboBoxItem Background="Red">Red</ComboBoxItem>
<ComboBoxItem Background="Blue">Blue</ComboBoxItem>
<ComboBoxItem Background="Green">Green</ComboBoxItem>
<ComboBoxItem Background="Yellow">Yellow</ComboBoxItem>
<ComboBoxItem Background="Black">Black</ComboBoxItem>
</ComboBox>
</DataTemplate>
</ResourceDictionary>
我们得到了一个包括一些ComboBoxItems的 ComboBox。 唯一重要的就是通过设计工具确保字符值以或数值被绑定到.
下面我们添加了一些静态类来访问我们的Resource dictionary.
{
private static ResourceDictionary dictionary = (ResourceDictionary)Application.LoadComponent(new Uri("SilverlightControls.Design.Editos;component/EditorDictionary.xaml", UriKind.Relative));
public static DataTemplate ColorsComboBox
{
get
{
return dictionary["ColorsComboBox"] as DataTemplate;
}
}
}
这个类要做的就是加载Resource dictionary 并包含一个返回我们 DateTemplate的静态属性.
现在让我们看一个感兴趣的地方, 我们会创建一个显示DataTemplate的自定义inline editor.
{
public CustomInlineEditor()
{
this.InlineEditorTemplate = EditorDictionary.ColorsComboBox;
}
}
非常直接. PropertyValueEditor 一个有趣的地方 - 这个(我们用于设置DataTemplate)InlineEditorTemplate取自resource dictionary.
最后必须要说的是MyControl.MyStringProperty 有一个自定底 inline editor.
new DescriptionAttribute("I am a property"),
new DisplayNameAttribute("My String Property"),
new CategoryAttribute("My Category"),
new PropertyOrderAttribute(PropertyOrder.Early),
PropertyValueEditor.CreateEditorAttribute(typeof(CustomInlineEditor)));
在Blend里的效果:
然后,我们选取“Green”.
在UI和XAML之间来回进行驱动的是ComboBox 到 StringValue的绑定.
我想从这个练习中得到的不应该是“rainbow colored ComboBoxes不错” 或“要将任何元素都做为一个inline editor”.
现在我们看到editor 的样子以及它是如何工作的, 我们应该熟悉3种类型的属性 editors.
Inline Property Editor :下面的“单行并有属性名称和编辑框” 样式.
Extended Property Editor:有内部的editor, 但也可根据用户操作弹出或占用一些区域(显示).
Dialog property editor – 一个具有触发对话框按钮的Inline property editor.
Expended Property Editor
正如上面所见, 一个expended property editor 就是一个inline editor,其基于用户操作来占用更大的屏幕区域.
让我们看看如何创建它.
我们着手在EditorResources.xaml文件中创建另一个 DataTemplate(InlineValueEditorTemplate):
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding StringValue}" />
<PropertyEditing:EditModeSwitchButton />
</StackPanel>
</DataTemplate>
我们看到仅有一个绑定StringValue的TextBox。我们在前面的inline property editor中已看到过.
有趣的是这里有一个“EditModeSwitchButton”. 它内置一个extensibility 按钮,它可展开/收缩extended template
视图.这个按钮的作用就是链接到 extensibility 的PropertyValueEditorCommands,该命令负责显示或隐藏extended视图.
现在我们有了InlineValueEditorTemplate, 下面添加另外一个 DataTemplate(ExtendedValieEditorTemplate):
<ListBox SelectedItem="{Binding StringValue}">
<ListBox.ItemsSource>
<x:Array Type="{x:Type System:String}">
<System:String>Hello</System:String>
<System:String>World</System:String>
<System:String>foo</System:String>
<System:String>bar</System:String>
</x:Array>
</ListBox.ItemsSource>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
尽管这个DataTemplate 看着有点意思, 然而实际上并不是这样. 它仅是一组在Listbox中作为 TextBlock显示出来的字符串.
唯一有趣的是它是我们将这个ListBox 的SelectedItem 绑定到 StringValue.
下面, 我们会在EditorDictionary类中创建这两个强类型(命名)的属性:
{
get
{
return dictionary["SimpleTextBox"] as DataTemplate;
}
}
public static DataTemplate HelloWorldListBox
{
get
{
return dictionary["HelloWorldListBox"] as DataTemplate;
}
}
最后,我们创建一个ExtendedValuePropertyEditor 来使用我们上面的两个新的 DataTemplates:
{
public CustomExtendedEditor()
{
this.InlineEditorTemplate = EditorDictionary.SimpleTextBox;
this.ExtendedEditorTemplate = EditorDictionary.HelloWorldListBox;
}
}
还有要把CustomExtendedEditor绑定到我们的 MyStringProperty 上:
new DescriptionAttribute("I am a property"),
new DisplayNameAttribute("My String Property"),
new CategoryAttribute("My Category"),
new PropertyOrderAttribute(PropertyOrder.Early),
PropertyValueEditor.CreateEditorAttribute(typeof(CustomExtendedEditor)));
这是在 Blend 中的效果:
点击该按钮之后 ,我们就得到了这个ExtendedEditorTemplate 弹出框:
我们点击另一个按钮会看到ExtendedEditorTemplate 在data pane里占用了更多的空间:
选择这个列表项中的任一个值都会造成Textbox 和后面属性的更新:
并再点击按钮时会关闭该extended editor:
Dialog Property Editor
除了用 Extended template 显示 inline editor, 我们可能打算用弹出对话框方式来显示(inline editor).
我们使用已存在的resource dictionary来创建一个对话框 editor 。
{
public CustomDialogEditor()
{
this.InlineEditorTemplate = EditorDictionary.SimpleTextBox;
this.DialogEditorTemplate = EditorDictionary.HelloWorldListBox;
}
}
我们需要将custom dialog editor 绑定到MyStringProperty上:
new DescriptionAttribute("I am a property"),
new DisplayNameAttribute("My String Property"),
new CategoryAttribute("My Category"),
new PropertyOrderAttribute(PropertyOrder.Early),
PropertyValueEditor.CreateEditorAttribute(typeof(CustomDialogEditor)));
当在 Blend 中运行时:
然后在该对话模中修改值也将会造成Textbox 和后面属性值的变化:
尽管Dialog property editors 与extended property editors有相似的API, 但却有一个主要不同– 它支持事务
(transactions).
您看到的“OK” 和“Cancel” 按钮就是基于触发CommitTransaction 或 AbortTransaction 命名而定义的.
那么, 如果我们在选择“World”之后点击 cancel,该属性会回复到它的原始值“foo”:
希望您从这个tutorial中学到一些知识, 它包括许多 knocks 和 crannies, 但这应该让您明确您自己要采用的方式,
-- Justin Angel
Microsoft Silverlight Toolkit Program Manager
译者:能看到这里的都不是凡人,起码你有时间一路阅读下来。
好了,今天的内容就到这里。
原文链接:http://www.cnblogs.com/daizhj/archive/2008/11/27/1342175.html
作者: daizhj, 代震军
Tags: silverlight,blend,wpf,design-time,run-time,interface,Extensibility,设计时,运行时,扩展
网址: http://daizhj.cnblogs.com/