WPF XAML Change Style Template Property for Some Elements

£可爱£侵袭症+ 提交于 2020-01-30 11:27:26

问题


In a WPF application I have a style used for buttons:

<Style TargetType="Button" x:Key="ButtonEllipse">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <StackPanel Orientation="Vertical">
                    <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0 0 0 10"/>
                    <Image x:Name="ButtonImage" HorizontalAlignment="Center" VerticalAlignment="Center" Stretch="None" Source="/MyProject;component/Images/ButtonEllipse.png"/>
                </StackPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

For most buttons that is OK but for one specific instance I want to use the same template but change the image to ButtonEllipseNew.png (which is the value of a view model property). The button is defined like this:

<Button Content="Test" Style="{StaticResource ButtonEllipse}">
</Button>

How can I change the value of the image source in the template only for this specific button? I want to bind the source to a property in the view model.


回答1:


I would write a custom control that looks something like this:

internal class IconButton : Button
{
    public ImageSource Source
    {
        get { return (ImageSource)GetValue(SourceProperty); }
        set { SetValue(SourceProperty, value); }
    }

    public static readonly DependencyProperty SourceProperty =
        DependencyProperty.Register("Source", typeof(ImageSource), typeof(IconButton), new PropertyMetadata(null));

}

Then edit your style to accommodate it:

<Style TargetType="{x:Type location:IconButton}" x:Key="ButtonEllipse">
<Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="{x:Type location:IconButton}">
            <StackPanel Orientation="Vertical">
                <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0 0 0 10"/>
                <Image x:Name="ButtonImage" HorizontalAlignment="Center" VerticalAlignment="Center" Stretch="None" Source="{TemplateBinding Source"/>
            </StackPanel>
        </ControlTemplate>
    </Setter.Value>
</Setter>

Where location is a xaml-defined namespace where the IconButton class is placed.

Then just set the Source property of your button. You can mess around with the Source property to set a default as well.




回答2:


I am afraid you can't reuse only a part of a ControlTemplate. You must define the template as a whole:

WPF: Is there a way to override part of a ControlTemplate without redefining the whole style?

What you could do is to bind the Source property of the Image in the template to some property that you can then set individually for each control to which the template is applied:

<Style TargetType="Button" x:Key="ButtonEllipse">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <StackPanel Orientation="Vertical">
                    <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0 0 0 10"/>
                    <Image x:Name="ButtonImage" HorizontalAlignment="Center" VerticalAlignment="Center" Stretch="None"
                                   Source="{Binding Tag, RelativeSource={RelativeSource AncestorType=Button}}"/>
                </StackPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
...
<Button Content="Test" Style="{StaticResource ButtonEllipse}" Tag="image.png" />



回答3:


In order to bind a property to your style you should do the following:

Create a user control let's name it ButtonImage.cs

    public class ButtonImage : Button
{
    public ImageSource Source
    {
        get
        {
            return (ImageSource)GetValue(SourceProperty);
        }
        set
        {
            SetValue(SourceProperty, value);
        }
    }

    public static readonly DependencyProperty SourceProperty =
        DependencyProperty.Register("Source", 
            typeof(ImageSource), 
            typeof(ButtonImage), 
            new PropertyMetadata(null));

}

I would create a ResourceDictionary so you can use it for all your styles. Let's name it Dictionary.xaml. An there you define your style like:

        <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                        xmlns:local="clr-namespace:WpfApplication4">
        <Style TargetType="{x:Type local:ButtonImage}" x:Key="ButtonEllipse">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type local:ButtonImage}">
                        <StackPanel Orientation="Vertical">
                            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0 0 0 10"/>
                            <Image x:Name="ButtonImage" HorizontalAlignment="Center" VerticalAlignment="Center" Stretch="None" Source="{TemplateBinding Source}"/>
                        </StackPanel>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ResourceDictionary>

Then in your view you can do:

<Window x:Class="WpfApplication4.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:wpfApplication4="clr-namespace:WpfApplication4"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800">
    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary 
                  Source="Dictionary.xaml">
                </ResourceDictionary>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>
    <Grid>
        <wpfApplication4:ButtonImage Margin="0,50,0,0" Content="Test" Source="{Binding Name}" Style="{StaticResource ButtonEllipse}" />
    </Grid>
</Window>


来源:https://stackoverflow.com/questions/49516233/wpf-xaml-change-style-template-property-for-some-elements

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!