It is always a good practice to ship your WPF/Silverlight controls with its design time experience. Design time experience can be extended with the help of design assemblies supplies by Microsoft
Steps :
Create your WPF/Silverlight control
Create a visual studio class library project and name it MyControls
Subclass a control of your choice and add one dependency property. I did that for a button control in my sample. I used this control to demonstrate the property Editor in design time extensibility
public class MyButton : Button
{
public double MyHeight
{
get { return (double)GetValue(MyHeightProperty); }
set { SetValue(MyHeightProperty, value); }
}
// Using a DependencyProperty as the backing store for MyHeight. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyHeightProperty =
DependencyProperty.Register("MyHeight", typeof(double), typeof(MyButton), new UIPropertyMetadata(0d));
}
Create a second class as above to demonstrate the category Editor concept in design time Extensibility . My second class is as follows
public class MyTextBox : TextBox
{
public double MyWidth
{
get { return (double)GetValue(MyWidthProperty); }
set { SetValue(MyWidthProperty, value); }
}
// Using a DependencyProperty as the backing store for MyWidth. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyWidthProperty =
DependencyProperty.Register("MyWidth", typeof(double), typeof(MyTextBox), new UIPropertyMetadata(20d));
}
Create the Design time project for the control
Create a class library project named MyControls.design and add reference to the following assemblies
Microsoft.Windows.Design.dll
MyControls.dll
Create a class which inherit from the IRegisterMetadata interface and write necessary code to update the metadatstore (a container of custom design-time attributes).
public class DesignMetaDataMain : IRegisterMetadata
{
#region IRegisterMetadata Members
public void Register()
{
AttributeTableBuilder builder = new AttributeTableBuilder();
new MyButtonMetadata().AddMetadata(builder);
new MyTextBoxMetadata().AddMetadata(builder);
MetadataStore.AddAttributeTable(builder.CreateTable());
}
#endregion
}
public class MyButtonMetadata
{
public void AddMetadata(AttributeTableBuilder tableBuilder)
{
//Property Editor
tableBuilder.AddCustomAttributes(
typeof(MyButton),
MyButton.MyHeightProperty,
new MyButtonCategoryAttribute(),
new EditorAttribute(typeof(TextExtendedEditor),
typeof(TextExtendedEditor)));
}
}
internal class MyButtonCategoryAttribute : CategoryAttribute
{
protected override string GetLocalizedString(string value)
{
return "MyButton";
}
}
public class MyTextBoxMetadata
{
public void AddMetadata(AttributeTableBuilder tableBuilder)
{
tableBuilder.AddCustomAttributes(typeof(MyTextBox), MyTextBox.MyWidthProperty, new MyTextBoxCategoryAttribute());
tableBuilder.AddCustomAttributes(typeof(MyTextBox), new EditorAttribute(typeof(MyTextBoxCategoryEditor), typeof(MyTextBoxCategoryEditor)));
}
}
internal class MyTextBoxCategoryAttribute : CategoryAttribute
{
protected override string GetLocalizedString(string value)
{
return "MyTextBox";
}
}
Category Editor definition
public class MyTextBoxCategoryEditor : CategoryEditor
{
public override bool ConsumesProperty(PropertyEntry property)
{
return true;
}
public override System.Windows.DataTemplate EditorTemplate
{
get
{
try
{
Resources myresourcedictionary = new Resources();
return myresourcedictionary["myTextBoxEditorTemplate"] as DataTemplate;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return null;
}
}
public override object GetImage(System.Windows.Size desiredSize)
{
return null;
}
public override string TargetCategory
{
get
{
return "MyTextBox";
}
}
}
Property Editor definition
public class TextExtendedEditor : ExtendedPropertyValueEditor
{
private Resources res = new Resources();
public TextExtendedEditor()
{
this.InlineEditorTemplate = res["myButtonEditorTemplate"] as DataTemplate;
}
}
Resource Dictionary code
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:PropertyEditing="clr-namespace:Microsoft.Windows.Design.PropertyEditing;assembly=Microsoft.Windows.Design"
x:Class="MyControls.Design.Resources" >
<DataTemplate x:Key="myButtonEditorTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0"
Content="{Binding StringValue}" Click="Button_Click"/>
<TextBox Text="{Binding StringValue}"
Grid.Column="1" />
<!--<PropertyEditing:EditModeSwitchButton Grid.Column="1" />-->
</Grid>
</DataTemplate>
<DataTemplate x:Key="myTextBoxEditorTemplate">
<Expander>
<ItemsControl ItemsSource="{Binding Path=Properties}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="Left"
Width="0.4*"
MinWidth="100"
MaxWidth="180" />
<ColumnDefinition SharedSizeGroup="Middle"
Width="0.6*" />
<ColumnDefinition SharedSizeGroup="Right"
Width="12" />
</Grid.ColumnDefinitions>
<PropertyEditing:PropertyContainer Grid.ColumnSpan="3"
PropertyEntry="{Binding}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Expander>
</DataTemplate>
</ResourceDictionary>
Build this project and copy the assembly to the bin\debug\design folder of the MyControls project. The design folder will not be there by default..you need to create a folder with that name. For deployment scenarios you must create a design folder on the location of the mycontrols.dll and place the design dll there.
Consume the control in a project
Create a WPF application and use the two controls created in project MyControls
<Window x:Class="WPFHost.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyControls;assembly=MyControls"
Title="Window1" Height="300" Width="300">
<StackPanel>
<local:MyButton MyHeight="100" Content="MyButton"/>
<local:MyTextBox MyWidth="200"
Text="MyTextBox"
/>
</StackPanel>
</Window>
You are done and you should be able to see a custom property editor in case of the myTextBox control and a custom property editor for myButton as shown below(Note that the dependency property we added for the controls are shown in a separate bucket in the property pages
Design time in Cider
| |
Design time in Blend
| |
No comments:
Post a Comment