开发者

Custom control defined in an assembly with ControlTemplates defined in another

开发者 https://www.devze.com 2023-04-13 05:58 出处:网络
I have created a library with custom controls to simplify some developments of my coworkers. I then have created a template in which I would like to give them the opportunity to modify default templat

I have created a library with custom controls to simplify some developments of my coworkers. I then have created a template in which I would like to give them the opportunity to modify default templates and so on. After some researches, I found some information on Themes, Generic.xaml and ThemeInfo attribute but something doesn't work.

So my last attempt: - The control library with Theme attribute in AssemblyInfo.cs:

[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //où se trouvent les dictionnaires de ressources spécifiques à un thème
//(utilisé si une ressource est introuvable dans la page, 
// ou dictionnaires de ressources de l'application)
ResourceDictionaryLocation.ExternalAssembly //où se trouve le dictionnaire de ressources générique
//(utilisé si une ressource est introuvable dans la page, 
// dans l'application ou dans l'un des dictionnaires de ressources spécifiques à un thème)

)]

All controls inherit from System.Windows.Control and have a static constructor with:

DefaultStyleKeyProperty.
         OverrideMetadata(typeof(Tire), new FrameworkPropertyMetadata(typeof(Tire))); 

Then, in the application, where this library is referenced, I have a Themes/Generic.xaml file with such definitions:

<Style TargetType="{x:Type g:Tire}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type g:Tire}">
                <Viewbox Name="view">
                    <Ellipse Stroke="Black" StrokeThickness="10" Width="30" 
                             Height="30"/>
                </Viewbo开发者_开发知识库x>
                <ControlTemplate.Triggers>
                    <DataTrigger Binding="{Binding Present}" Value="true">
                        <Setter TargetName="view" Property="Visibility" Value="Visible"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding Present}" Value="false">
                        <Setter TargetName="view" Property="Visibility" Value="Collapsed"/>
                    </DataTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

I also tried setting a key with {x:Type g:Tire}ou simplement g:Tire but without success: the controls are rendered without control templates in VS2010.

To successfully display the controls, I have to add the generic.xaml file as a ResourceDictionary in app.xaml, whereas I add the ThemeInfo attribute or not in this second assembly.

An other related issue: if in a window.xaml file or another control xaml file, to use the power of styles, I add:

<Style TargetType="{x:Type g:Tire}">
    <Setter Property="Width" Value="20"/>
</Style>

the system seems to override the style defined in generic.xaml and the control template is not rendered anymore. To check I looked at the Template property in the property grid and the origin of the value is referenced as "Defined in Style" instead of the classic "Inheritance" when a custom control is defined in the same assembly.

So my question, could someone point me where I should look to overcome this situation or help me find the right way to prepare such a setup : define controls in a Class library, and, using the default style mechanism, define the control templates in a generic.xaml file in a wpf application ?

Thanks in advance !

Update:

I've looked upon a few things and it is a bit more clear: as I don't intend to use theming in the general way, I have to set in some way the style system to use a resourcedictionnary defined in the customer library as the "generic" dictionary.

By adding ThemeInfo(...None, ...None) in the source assembly and addind the customer xaml file as resource in the customer assembly, I managed to change the value returned by DependencyPropertyHelper.GetValueSource(customControl1, Library.CustomControl.TemplateProperty).BaseValueSource from Style to Default, but Template is still overwritten if a style is defined in the application:

<Window x:Class="WpfApp.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525" xmlns:my="clr-namespace:Library;assembly=Library">
<Grid>
    <Grid.Resources>
        <Style TargetType="my:CustomControl"></Style>
    </Grid.Resources>
    <my:CustomControl HorizontalAlignment="Left" Margin="128,95,0,0" Name="customControl1" VerticalAlignment="Top" Height="157" Width="253" />
</Grid>

Moreover, in the property grid, the source of the Template property is still set as Style...

I guess I am now looking at a way to set the style as implicit or default or something.. (the one defined in the customer assembly for a control defined in the source assembly).


It is not entirely clear to me which part is not working and what template you want to give to your coworkers to modify the default appearance, but that's what you need to do with Custom Controls in WPF:

Create a custom control class inherited from

System.Windows.Controls.Control

You got the constructor part correctly, so the next step is to create a folder in the same project as your custom control with the name 'Themes' and add Generic.xaml in there. That's where the WPF will look for the default control template.

Define a style which implements your target type:

<Style TargetType="{x:Type local:Tire}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:Tire}">
                <!--  there goes your template: grids / stackpanels, etc -->

For each project where you want to use the control you have a chance to redefine the style:

<Style TargetType="{x:Type custom:Tire}">
    <Setter Property="Width" Value="150"/>
    <!-- any customer dependency property can be set here as well-->

If you want those properties to actually change you need to use TemplatedParent in your source assembly to bind those properties rather than hard-coding them.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号