0

I have a WPF application with a menu bar with some buttons to navigate to the different sections.

All the buttons have an style with a VisualState property, so all of them have a Normal, OnMouseOver and Pressed state different styles. And all the buttons, once pressed, execute a Command on the ModelView.

What i want is that each time a button is pressed, first it keeps the Pressed state until another button is pressed and second, it is possible to change the button state from the Command event executed at the ModelView side.

The Code:

<Style x:Key="MainButtonStyle" TargetType="Button">
        <Setter Property="Width" Value="120"/>
        <Setter Property="Height" Value="60"/>
        <Setter Property="Margin" Value="5"/>            
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Grid Background="White" x:Name="ButtonGrid">
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal"/>
                                <VisualState x:Name="MouseOver">
                                    <Storyboard>                                            
                                        <ColorAnimation Duration="0:0:0.3" Storyboard.TargetName="ButtonGrid" Storyboard.TargetProperty="Background.Color" To="Cyan"/>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Pressed">
                                    <Storyboard>
                                        <ColorAnimation Duration="0:0:0.2" Storyboard.TargetName="ButtonGrid" Storyboard.TargetProperty="Background.Color" To="DarkSalmon"/>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

The buttons using the style:

<ItemsControl Margin="10" Grid.Column="1" Grid.RowSpan="2" ItemsSource="{Binding HeaderButtons}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Button Style="{StaticResource MainButtonStyle}" Content="{Binding content}"
                            Command="{Binding DataContext.ChangePageContainerCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
                            CommandParameter="{Binding containerType}"/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>                
        </ItemsControl>

And i think that the ModelView is not relevant since it does nothing on the Button VisualState since i don't know how to pass it a reference to the Button caller (as parameter or something?).

I have seen in other posts that people recommend to use a ToggleButton in place of a Button and set the IsChecked to true, but i don“t know where should i set that property, i mean, should i set it at the XAML or at code? and how?

MorgoZ
  • 2,012
  • 5
  • 27
  • 54

1 Answers1

1

What i want is that each time a button is pressed, first it keeps the Pressed state until another button is pressed

What you want is a group of RadioButtons, but probably ones that are styled to look like normal Buttons. Here is a small example of some RadioButtons that look somewhat like Buttons:

<StackPanel Orientation="Horizontal">
    <StackPanel.Resources>
        <Style TargetType="{x:Type RadioButton}">
            <Setter Property="BorderBrush" Value="Blue" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type RadioButton}">
                        <Border Name="Border" CornerRadius="4" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="2" Padding="10, 5" VerticalAlignment="Top" Margin="0,0,5,0">
                            <ContentPresenter />
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter TargetName="Border" Property="Border.Background" Value="LightBlue" />
                            </Trigger>
                            <Trigger Property="IsChecked" Value="True">
                                <Setter TargetName="Border" Property="Border.Background" Value="LightGreen" />
                                <Setter TargetName="Border" Property="Border.BorderBrush" Value="Green" />
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </StackPanel.Resources>
    <RadioButton Content="Button 1" />
    <RadioButton Content="Button 2" />
    <RadioButton Content="Button 3" />
</StackPanel>

Note that I have added some basic state functionality using basic Triggers... using the VisualStateManager is simply unnecessary here and seems to be causing extra problems for you. The VisualStateManager really comes into its own when we write complex UserControls or CustomControls that require definite separate states. For your simple purposes, you should just use Triggers instead.

is it possible to change the button state from the Command event executed at the ModelView side?

The answer to your second question has been answered so many times before that UI won't go into it all again here. Suffice it to say that you can find details in the How to bind RadioButtons to an enum? question (or in many other online sources). In short though, you need to define an enum, declare an EnunmToBoolConverter to enable you to data bind your enum to the bool IsChecked property of each RadioButton. You will then be able to set each Button to be selected or not from the view model.

Community
  • 1
  • 1
Sheridan
  • 68,826
  • 24
  • 143
  • 183