简体   繁体   中英

Button Template style when selected

I have a mvvm design pattern set up to do commands and workspaces so that a button is pressed and the proper workspace displays. The buttons have a template binding to pull in the proper image for the template based on the command. I have added another field to the command for a SelectedTemplateResource for when the button is selected out of the array of buttons. The DataTemplate is pulled into the mainwindow to display the buttons.

<DataTemplate x:Key="CommandsTemplate">
    <ItemsControl ItemsSource="{Binding}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal" />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Button Command="{Binding Path=Command}" Content="{Binding Path=DisplayName}" Template="{Utilities:BindableResource {Binding Path=TemplateResource}}">
                    <Button.Style>
                        <Style TargetType="Button">
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding Path=Command}">
                                    <Setter Property="Template">
                                        <Setter.Value>

                                        </Setter.Value>
                                    </Setter>
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </Button.Style>
                </Button>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</DataTemplate>

Want I want to do is set the value of the setter to the SelectedTemplateResource like so in the Template of the button called TemplateResource. These are all handled through the mainwindowviewmodel to set the appropriate template per button and it works well but I'm not sure how to finish the selected state.

Also, I'm not entirely sure if I should be setting the datatrigger binding to the command path.

Can anybody help me with figuring out how to set the selected state of a button using the design mentioned above?

Cheers.

EDIT I get the use of the togglebutton trigger however the binding is not working. Heres some more information as for some reason I keep getting key is null error in my app.xaml.cs

The ToggleButton is a datatemplate in a file called MainWindowResources.xaml ( ResourceDictionary ). The MainWindow.xaml file pulls in this data template. I have a bindableresource class to help with the static resource for the resource file.

public class BindableResource : StaticResourceExtension
{
    #region Fields
    private static readonly DependencyProperty dummyProperty;
    #endregion


    #region Properties
    /// <summary>
    /// Gets and sets my binding.
    /// </summary>
    public Binding MyBinding { get; set; }
    #endregion


    #region Constructor
    /// <summary>
    /// Static contruction of the dummy dependency property.
    /// </summary>
    static BindableResource()
    {
        dummyProperty = DependencyProperty.RegisterAttached("Dummy", typeof(string), typeof(DependencyObject), new UIPropertyMetadata(null));
    }

    /// <summary>
    /// Constructor.
    /// </summary>
    public BindableResource()
    {
    }

    /// <summary>
    /// Constructor with binding to set.
    /// </summary>
    /// <param name="binding"></param>
    public BindableResource(Binding binding)
    {
        MyBinding = binding;
    }
    #endregion


    #region External Members
    /// <summary>
    /// Get the resource key to bind to the resource.
    /// </summary>
    /// <param name="serviceProvider"></param>
    /// <returns></returns>
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        var target = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
        var targetObject = (FrameworkElement)target.TargetObject;

        MyBinding.Source = targetObject.DataContext;
        var DummyDO = new DependencyObject();
        BindingOperations.SetBinding(DummyDO, dummyProperty, MyBinding);

        ResourceKey = DummyDO.GetValue(dummyProperty);

        return base.ProvideValue(serviceProvider);
    }
    #endregion
}

However this does not work for the triggers setter value.

<DataTemplate>
                <ToggleButton Command="{Binding Path=Command}" Content="{Binding Path=DisplayName}" Template="{Utilities:BindableResource {Binding Path=TemplateResource}}">
                    <ToggleButton.Style>
                        <Style TargetType="ToggleButton">
                            <Style.Triggers>
                                <Trigger Property="IsChecked" Value="True">
                                    <Setter Property="Template" Value="{Utilities:BindableResource {Binding Path=SelectedTemplateResource}}" />
                                </Trigger>
                            </Style.Triggers>
                        </Style>
                    </ToggleButton.Style>
                </ToggleButton>
            </DataTemplate>

Any thoughts or ideas?

I'm not sure I've understood what you want exactly. You want to change the button's template if it's selected yes?

Firstly a standard button doesn't have a the notion of being "selected". You want a ToggleButton for that. That way you can trigger on its IsChecked property to set your template.

<DataTemplate x:Key="CommandsTemplate">
    <ItemsControl ItemsSource="{Binding}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal" />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <ToggleButton Command="{Binding Path=Command}" Content="{Binding Path=DisplayName}" Template="{Utilities:BindableResource {Binding Path=TemplateResource}}">
                    <ToggleButton.Style>
                        <Style TargetType="ToggleButton">
                            <Style.Triggers>
                                <Trigger Property="IsChecked" Value="True">
                                    <Setter Property="Template" Value="{Utilities:BindableResource {Binding DataContext.SelectedTemplateResource}}">
                                </Trigger>
                            </Style.Triggers>
                        </Style>
                    </ToggleButton.Style>
                </ToggleButton>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</DataTemplate>

After finding out this really is not possible to do in pure xaml I brought out the c# and create a custom control... this is very basic and can be improved on and I will have change a bit of it but ultimately a custom control solves the issue so that you can hit the click event from within the resource dictionary and change the template on the fly.

public class TabButton : Button
{
    public static readonly DependencyProperty SelectedTemplateProperty = 
        DependencyProperty.Register("SelectedTemplate", typeof(ControlTemplate), typeof(TabButton));

    public ControlTemplate SelectedTemplate
    {
        get { return base.GetValue(SelectedTemplateProperty) as ControlTemplate; }
        set { base.SetValue(SelectedTemplateProperty, value); }
    }

    public TabButton()
    {
        this.Click += new RoutedEventHandler(TabButton_Click);
    }

    ~TabButton()
    {

    }

    public void TabButton_Click(object sender, RoutedEventArgs e)
    {
        ControlTemplate template = (ControlTemplate)this.FindResource("Environmental Template Selected");
        (sender as TabButton).Template = template;
    }
}

Cheers.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM