0

How can I change a Button template dynamically?

I have a ComboBox where by changing his selected value I want to change a Button Template. This is what I have been trying to do:

<Window.Resources>
    <ControlTemplate x:Key="ButtonControlTemplate1" TargetType="{x:Type Button}">
        <Grid>
            <Rectangle Fill="#FF2D2D7A" Margin="7.5,9.5,8.5,11" Stroke="Black"
                       RadiusX="45" RadiusY="45" StrokeThickness="6"/>
        </Grid>
    </ControlTemplate>
    <ControlTemplate x:Key="ButtonControlTemplate2" TargetType="{x:Type Button}">
        <Grid>
            <ed:RegularPolygon Fill="#FFE7F9C9" Height="Auto" InnerRadius="0.47211"
                               Margin="20.5,16,15.5,8" PointCount="5" Stretch="Fill"
                               Stroke="Black" StrokeThickness="6" Width="Auto"/>
        </Grid>
    </ControlTemplate>
</Window.Resources>

<Grid x:Name="LayoutRoot">
    <ComboBox Name="GroupBoxHeaderComboBox" ItemsSource="{Binding Path=collection}" 
              DisplayMemberPath="Key" Height="52" Margin="211.5,60,230.5,0"
              VerticalAlignment="Top" SelectedIndex="1"/>
    <Button Content="Button" HorizontalAlignment="Left" Height="102" Margin="47.5,0,0,91"
            VerticalAlignment="Bottom" Width="132"
            Template="{DynamicResource ButtonControlTemplate2}"/>
    <Button Content="Button" HorizontalAlignment="Right" Height="112.5" Margin="0,0,27.5,85"
            VerticalAlignment="Bottom" Width="153"
            Template="{DynamicResource ButtonControlTemplate1}"/>
    <Button Content="Button" Height="102" Margin="239.5,0,252.5,13.5"
            VerticalAlignment="Bottom"
            Template="{Binding ElementName=GroupBoxHeaderComboBox, Path=SelectedItem.Value}"/>
</Grid>

And here are the associated Templates:

<Window.Resources>
    <ControlTemplate x:Key="ButtonControlTemplate1" TargetType="{x:Type Button}">
        <Grid>
            <Rectangle Fill="#FF2D2D7A" Margin="7.5,9.5,8.5,11" Stroke="Black"
                       RadiusX="45" RadiusY="45" StrokeThickness="6"/>
        </Grid>
    </ControlTemplate>
    <ControlTemplate x:Key="ButtonControlTemplate2" TargetType="{x:Type Button}">
        <Grid>
            <ed:RegularPolygon Fill="#FFE7F9C9" Height="Auto" InnerRadius="0.47211"
                               Margin="20.5,16,15.5,8" PointCount="5" Stretch="Fill"
                               Stroke="Black" StrokeThickness="6" Width="Auto"/>
        </Grid>
    </ControlTemplate>
</Window.Resources>

And the code behind:

public partial class MainWindow : Window
{
    public Dictionary<string, string> collection
    {
        get;
        private set;
    }

    public MainWindow()
    {
        this.InitializeComponent();
        DataContext = this;
        collection = new Dictionary<string, string>() 
        {
            { "DynamicResource ButtonControlTemplate2", "{DynamicResource ButtonControlTemplate2}"},
            { "DynamicResource ButtonControlTemplate1", "{DynamicResource ButtonControlTemplate2}"},

        };
    // Insert code required on object creation below this point.
    }
}

Is there another genric way to acomplish this?... I want that most of the code would be xaml.

EDIT:

Is there a point to do it using a style? Let's say I want more then one object to act, otherwise is there a point to change the style and to do it all from there?

3 Answers 3

2
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            DataContext = this;
        }

        public Dictionary<string, ControlTemplate> collection
        {
            get
            {
                Dictionary<string, ControlTemplate> controlTemplates = new Dictionary<string, ControlTemplate>();
                controlTemplates.Add("ButtonControlTemplate1", FindResource("ButtonControlTemplate1") as ControlTemplate);
                controlTemplates.Add("ButtonControlTemplate2", FindResource("ButtonControlTemplate2") as ControlTemplate);
                return controlTemplates;
            }
        } 
    }
Sign up to request clarification or add additional context in comments.

2 Comments

i seem to have a problem i am putting FindResource inside the VM and i have no acsses to hom can you please help with it ?
Control templates and other resources belong in the view and your VM should not reference your view if following MVVM. I would store the keys in the VM ("ButtonControlTemplate1", "ButtonControlTemplate2") and use some code behind in the view class to map the keys to a ControlTemplatwe using FindResource. If you want to store the ControlTemplates in the VM, then either create them in the VM using code behind or have the view populate the ControlTemplate collection in the VM in its Loaded handler.
0

Create a ControlTemplate in Windows resource,

<Window.Resources>
    <ControlTemplate x:Key="GreenTemplate" TargetType="{x:Type Button}">
        <Grid>
            <Ellipse Fill="Green"/>
            <ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
        </Grid>
    </ControlTemplate>
</Window.Resources>

Now in run time you can change the template property of button.

    private void Button_Clicked(object sender, RoutedEventArgs e)
    {
        Button btn = e.OriginalSource as Button;
        if (btn != null)
        {
            btn.Template = FindResource("GreenTemplate") as ControlTemplate;
        }
    }

Comments

0

You can use a data trigger and do it all in xaml.

This uses a tree but the concept is the same

<Window x:Class="WpfBindingTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfBindingTest"
Title="Window3" Height="300" Width="300"  Name="win3" >
<Window.Resources>
    <XmlDataProvider x:Key="treeData" XPath="*">
        <x:XData>
            <Items Name="Items" xmlns="">
                <Item1/>
                <Item2>
                    <Item22/>
                    <Item12/>
                    <Item13>
                        <Item131/>
                        <Item131/>
                    </Item13>
                </Item2>
            </Items>
        </x:XData>
    </XmlDataProvider>
    <HierarchicalDataTemplate ItemsSource="{Binding XPath=child::*}" x:Key="template">
        <TextBlock Name="textBlock" Text="{Binding Name}"/>
    </HierarchicalDataTemplate>
</Window.Resources>
<StackPanel>
<TreeView ItemTemplate="{StaticResource template}"
          Name="treeView"
          ItemsSource="{Binding Source={StaticResource treeData}}">
    <TreeView.ItemContainerStyle>
        <!--Using style setter to set the TreeViewItem.IsExpanded property to true, this will be applied
  to all TreeViweItems when they are generated-->
        <Style TargetType="{x:Type TreeViewItem}">
            <Setter Property="IsExpanded" Value="True"/>
        </Style>
    </TreeView.ItemContainerStyle>
</TreeView>
    <Button Width="120" Height="30">
        <Button.Style>
            <Style TargetType="Button">
                <Setter Property="Content" Value="Default" />
                <Style.Triggers>
                    <DataTrigger Binding="{Binding ElementName=treeView, Path=SelectedItem.Name}" Value="Item12">
                        <Setter  Property="Content" Value="Now changed" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Button.Style>
    </Button>

from here.

(I just googled to get an example faster)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.