Wpf ToggleButton Command Binding Data Trigger - wpf

I have a toggle button that has two data triggers that are bound to the buttons IsChecked property. Within the Data triggers I am setting the buttons content and also its command property. The problem that I am having is that when you click the button the data trigger is changing the command value and then firing the command. Is it possible to have the command fire first then the data trigger? Here is the code.
<ToggleButton x:Name="commandToggleButton" Grid.Row="0" Height="30" HorizontalAlignment="Left" Margin="26,24,0,0" VerticalAlignment="Top" Width="75">
<ToggleButton.Style>
<Style TargetType="ToggleButton">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=commandToggleButton, Path=IsChecked}" Value="False">
<Setter Property="Content" Value="Build" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Command" Value="{Binding Build}" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=commandToggleButton, Path=IsChecked}" Value="True">
<Setter Property="Content" Value="Cancel" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Command" Value="{Binding CancelBuild}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
What I would like to happen is that when the button is clicked the first time for the Build command to be fired, then if it is clicked the second time for the CancelBuild command to be fired.

Keep it simple:
<ToggleButton IsChecked="{Binding EnableBuild}" FontWeight="Bold">
<ToggleButton.Style>
<Style TargetType="ToggleButton">
<Style.Triggers>
<Trigger Property="IsChecked" Value="False">
<Setter Property="Content" Value="Build" />
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content" Value="Cancel" />
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
ViewModel:
public Command Build {get;set;}
public Command Cancel {get;set;}
//...
private bool _enableBuild;
public bool EnableBuild
{
get { return _enableBuild; }
set
{
_enableBuild = value;
NotifyPropertyChange(() => EnableBuild);
if (value)
Build.Execute();
else
Cancel.Execute();
}
}

Related

Data Trigger Based on Element Activity WPF

I've got a button that is only conditionally enabled. I'd like to change the button's tooltip if the button is enabled or disabled.
<Button Name="OkButton" VerticalAlignment="Center" Command="{Binding Path=OkCommand}"
CommandParameter="{Binding}" Click="OkButtonClick" Content="OK">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="ToolTipService.ShowOnDisabled" Value="True" />
<Setter Property="ToolTip" Value="OK" />
<Style.Triggers>
<DataTrigger ***SomeCondition*** Value="False">
<Setter Property="ToolTip" Value="OK Disabled" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
I know that I can probably bind to some property in my view model, but I would like to know if there's a way to handle this all in XAML.
it can be Trigger, not DataTrigger:
<Trigger Property="IsEnabled" Value="False">
<Setter Property="ToolTip" Value="OK Disabled" />
</Trigger>

Value cannot be null. Parameter name: from WPF button binding datatrigger

I've been struggeling with this issue today when as soon as I try to bind a data trigger on a button I get this issue and I can't find our the issue. The button is contained in a listview which is bound to a dataset.
There is my button code:
<Button
Grid.Row="1"
Grid.Column="0"
Click="BtnAddToCart_Click"
MinWidth="230">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Visibility" Value="Hidden"/>
<Setter Property="Margin" Value="7,5,0,0"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=OrderQty, Converter={StaticResource GreaterThanZero}}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
<Button.Template>
<ControlTemplate>
<WrapPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
<WrapPanel.Style>
<Style TargetType="{x:Type WrapPanel}">
<Setter Property="Background" Value="#ec3c42"/>
<Setter Property="TextBlock.Foreground" Value="White"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="White"/>
<Setter Property="Cursor" Value="Hand"></Setter>
<Setter Property="TextBlock.Foreground" Value="#ec3c42"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</WrapPanel.Style>
<WrapPanel.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Padding" Value="10,10" />
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="FontSize" Value="15"/>
</Style>
</WrapPanel.Resources>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Text="Ajouter aux Commandes"></TextBlock>
<fa:FontAwesome Visibility="Hidden" VerticalAlignment="Center" HorizontalAlignment="Right" Icon="check">
<fa:FontAwesome.Triggers>
<DataTrigger Binding="{Binding Path=ShowAsChecked}" Value="true">
<Setter Property="Visibility" Value="Visible"></Setter>
</DataTrigger>
</fa:FontAwesome.Triggers>
</fa:FontAwesome>
</WrapPanel>
</ControlTemplate>
</Button.Template>
</Button>
The issue seems to happen when I add this piece of code:
<fa:FontAwesome.Triggers>
<DataTrigger Binding="{Binding Path=ShowAsChecked}" Value="true">
<Setter Property="Visibility" Value="Visible"></Setter>
</DataTrigger>
</fa:FontAwesome.Triggers>
When I remove the trigger the code run as expected.
Even when I bind it to a property that is working on a different level it doesn't work.
I tried changing the binding to:
Binding="{Binding Path=OrderQty, Converter={StaticResource GreaterThanZero}}
and it's still giving me the error. I tried to look up some code example but didn't find anything about that issue (since the error is pretty common it's hard to tell what is going on).
Try
<fa:FontAwesome Visibility="Hidden" VerticalAlignment="Center" HorizontalAlignment="Right" Icon="check">
<fa:FontAwesome.Style>
<Style TargetType="fa:FontAwesome">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=ShowAsChecked}" Value="true">
<Setter Property="Visibility" Value="Visible"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</fa:FontAwesome.Style>
</fa:FontAwesome>

Toggle button - change icon on click

I have an app in WPF. I am using entypo icons and i decalred one as a resource:
<Grid.Resources>
<iconPacks:Entypo x:Key="PlayIcon" Width="50" Height="30" Kind="ControllerPlay"></iconPacks:Entypo>
</Grid.Resources>
Let's say I have two icons like this ( play/pause icon) and I want to change between them when the user clicks on ToggleButton. I came up with something like this, but unfortunately, it's not working:
<ToggleButton>
<Image>
<Image.Style>
<Style TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=ToggleButton}, Path=IsChecked}"
Value="true">
<Setter Property="Source"
Value="{StaticResource PauseIcon}" />
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=ToggleButton}, Path=IsChecked}"
Value="false">
<Setter Property="Source"
Value="{StaticResource PlayIcon}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</ToggleButton>
Could anyone tell me if I can achieve it like this (with slight modifications) or point me into right direction?
You can't set the Source of an Image to a PackIconEntypo. Set the Content property of the ToggleButton instead:
<ToggleButton>
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Setter Property="Content" Value="{StaticResource PlayIcon}" />
<Style.Triggers>
<Trigger Property="IsChecked" Value="true">
<Setter Property="Content" Value="{StaticResource PauseIcon}" />
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>

Change image and textblock foreground on TabItem = IsSelected

I have some TabItems, each one containg one image and a textblock. Here is the code:
<TabItem.Header>
<ContentControl>
<ContentControl.Template>
<ControlTemplate>
<StackPanel x:Name="sp" Orientation="Horizontal">
<Image x:Name="img" Source="img0.png"/>
<TextBlock x:Name="tb" Text="Tab1" VerticalAlignment="Center" Foreground="Green"/>
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="TabItem.IsSelected" Value="True">
<Setter TargetName="img" Property="Source" Value="img1.png" />
<Setter TargetName="tb" Property="Foreground" Value="Red" />
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
<Trigger SourceName="sp" Property="IsMouseOver" Value="True">
<Setter TargetName="img" Property="Source" Value="img1.png" />
<Setter TargetName="tb" Property="Foreground" Value="Red" />
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ContentControl.Template>
</ContentControl>
What I'm trying to achieve is to change the image's source and textblock's foreground value when the TabItem is selected. The IsMouseOver behaviour is working properly but the TabItem.IsSelected is not working as expected.
Basically this code is not doing what I'm thinking it should do:
<Trigger Property="TabItem.IsSelected" Value="True">
<Setter TargetName="img" Property="Source" Value="img1.png" />
<Setter TargetName="tb" Property="Foreground" Value="Red" />
<Setter Property="FontWeight" Value="Bold"/>
Please share your opinion.
Thank you.
You are trying to reach the IsSelected property of the TabItem from the TabItem.Header and that can't be accomplished with an ordinary Trigger. Instead, you need to use a DataTrigger so that you can Bind to the IsSelected property with a RelativeSource Binding:
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=
{x:Type TabItem}}}" Value="True">
<Setter TargetName="img" Property="Source"
Value="/WpfApplication1;component/Images/Tulips.jpg" />
<Setter TargetName="tb" Property="Foreground" Value="Red" />
<Setter Property="TextElement.FontWeight" Value="Bold"/>
</DataTrigger>

Generic Button Template

I have the following button style that has a cross in it and is used for a close button on a TabItem
<Button Grid.Column="2"
Width="15"
Height="15"
HorizontalAlignment="Center"
VerticalAlignment="Center"
DockPanel.Dock="Right"
AttachedCommand:CommandBehavior.Event="Click"
AttachedCommand:CommandBehavior.Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.CloseWorkspaceCommand}">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Focusable" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid Background="{TemplateBinding Background}">
<Path x:Name="ButtonPath"
Margin="3"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="M0,0 L1,1 M0,1 L1,0"
SnapsToDevicePixels="True"
Stretch="Uniform"
Stroke="{DynamicResource CloseButtonStroke}"
StrokeEndLineCap="Flat"
StrokeStartLineCap="Flat"
StrokeThickness="2"/>
</Grid>
<ControlTemplate.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=TabItem}}"
Value="false" />
<Condition Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=TabItem}}"
Value="false" />
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Visibility" Value="Hidden" />
</MultiDataTrigger.Setters>
</MultiDataTrigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Visibility" Value="Hidden" />
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background"
Value="{DynamicResource CloseButtonBackgroundHighlighted}" />
<Setter TargetName="ButtonPath"
Property="Stroke"
Value="{DynamicResource CloseButtonStrokeHighlighted}" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background"
Value="{DynamicResource CloseButtonBackgroundPressed}" />
<Setter TargetName="ButtonPath"
Property="Stroke"
Value="{DynamicResource CloseButtonStroke}" />
<Setter TargetName="ButtonPath"
Property="Margin"
Value="2.5,2.5,1.5,1.5" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.Style>
</Button>
This produces
I want to add a CheckButton styled to show a pin next to the close button like VS2012. I can do this no problem, but I want to place the CheckBox inside the same button template above so I get highlighting when the mouse is over the area. The problem is the button above contains the Path that draws the 'X'.
Is there a was I can make the button style above generic so I can include either the 'X' Path or the CheckBox, without replicating all the trigger stuff?
Thanks for your time.
I would approach this by creating my button class like ToolBarButton below and have a dependency property ButtonType. I will set ButtonType on the ToolBarButton.
public enum ButtonType
{
Close =0,
Pin
}
public class ToolBarButton : Button
{
public ButtonType ButtonType
{
get { return (ButtonType)this.GetValue(ButtonTypeProperty); }
set { this.SetValue(ButtonTypeProperty, value); }
}
public static readonly DependencyProperty ButtonTypeProperty = DependencyProperty.Register(
"ButtonType", typeof(ButtonType), typeof(ToolBarButton), new PropertyMetadata(ButtonType.Close));
}
in xaml:
<local:ToolBarButton ButtonType="Pin"/>
Then I will add the trigger in style to check for buttontype and apply the controltemplate containing checkbox
<Style.Triggers>
<Trigger Property="ButtonType" Value="Pin">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<CheckBox/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>

Resources