MultiDataTrigger with Custom DependencyProperty - c#

I have a MultiDataTrigger. I can bind to a DependencyProperty (DP) of the control and a view model property like this
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsSelected, RelativeSource={RelativeSource Self}}" Value="True"/>
<Condition Binding="{Binding PerformTextSearchesInCommentary}" Value="True"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Background" Value="LightGray"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
</Style.Triggers>
Great. But now, I want to use my own custom DP "HasTextMatch", which is defined in a static class. I can do this with a standard trigger like
<Style.Triggers>
<Trigger Property="Helpers:DataGridTextSearch.HasTextMatch" Value="True">
<Setter Property="Background" Value="LightGray"/>
</Trigger>
</Style.Triggers>
But I now want to include another Property. I have tried
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<!--<Condition Property="Helpers:DataGridTextSearch.HasTextMatch" Value="True"/>--> This obviously won't work.
<Condition Binding="{Binding Helpers:DataGridTextSearch.HasTextMatch, RelativeSource={RelativeSource Self}}" Value="True"/>
<Condition Binding="{Binding PerformTextSearchesInCommentary}" Value="True"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Background" Value="LightGray"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
</Style.Triggers>
But this does not work. I have searched but cannot seem to find out how to do this. How can I get the binding to my custom DP?
Thanks for your time.

The DataGridTextSearch.HasTextMatch property is an attached property. Please use the following Condition:
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=(Helpers:DataGridTextSearch.HasTextMatch), RelativeSource={RelativeSource Self}}>
...
Additional information about property path (including attached properties) can be found here: PropertyPath XAML Syntax, MSDN.

Related

MultiDataTrigger with multiple ComboBoxes WPF

I would like to enable button only when all specified ComboBoxes have values. However, as soon as I add a second condition, button is enabled from the start
Here is my code
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding ElementName=SensorPartNumberComboBox, Path=SelectedValue}" Value="{x:Null}"/>
<Condition Binding="{Binding ElementName=SensorTypeComboBox, Path=SelectedValue}" Value="{x:Null}"/>
<Condition Binding="{Binding ElementName=SensorBrandNameComboBox, Path=SelectedValue}" Value="{x:Null}"/>
<Condition Binding="{Binding ElementName=DimmingProtocolComboBox, Path=SelectedValue}" Value="{x:Null}"/>
<Condition Binding="{Binding ElementName=Wired_WirelessComboBox, Path=SelectedValue}" Value="{x:Null}"/>
</MultiDataTrigger.Conditions>
<Setter Property="IsEnabled" Value="False"/>
</MultiDataTrigger>
</Style.Triggers>
I would appreciate any help!
MultiDataTrigger requires all of the conditions to be true for it to take effect. I.e. it's equivalent to a logical AND.
In your example, if any value is non-null, the trigger won't take effect and the button will remain enabled.
For a logical OR, instead of using MultiDataTrigger, just use multiple DataTrigger. If any condition of any trigger is true, then that trigger will take effect, with precedence over the default setter for the property in the style.
For example:
<Setter Property="IsEnabled" Value="True"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=SensorPartNumberComboBox, Path=SelectedValue}" Value="{x:Null}">
<Setter Property="IsEnabled" Value="False"/>
<DataTrigger/>
<DataTrigger Binding="{Binding ElementName=SensorTypeComboBox, Path=SelectedValue}" Value="{x:Null}">
<Setter Property="IsEnabled" Value="False"/>
<DataTrigger/>
<DataTrigger Binding="{Binding ElementName=SensorBrandNameComboBox, Path=SelectedValue}" Value="{x:Null}">
<Setter Property="IsEnabled" Value="False"/>
<DataTrigger/>
<DataTrigger Binding="{Binding ElementName=DimmingProtocolComboBox, Path=SelectedValue}" Value="{x:Null}">
<Setter Property="IsEnabled" Value="False"/>
<DataTrigger/>
<DataTrigger Binding="{Binding ElementName=Wired_WirelessComboBox, Path=SelectedValue}" Value="{x:Null}">
<Setter Property="IsEnabled" Value="False"/>
<DataTrigger/>
</Style.Triggers>
Alternatively, you might consider putting the logic in your view model, with a single bool property you bind to, and which is set according to the bound SelectedValue properties for the various ComboBox controls.
Yet another alternative would be to use MultiBinding to bind the five view model properties that are bound to the ComboBox.SelectedValue properties, with a IMultiValueConverter that implements the logic.
Of course, these last two options work only if you've got a proper view model with binding set up in the first place (something I strongly encourage, if you haven't already).

Using "multiple" MultiDataTrigger

I'm trying to show/hide buttons on ListBox items by using multiple data triggers. The problem it doesn't work properly.
The changes of the properties are triggering well however the conditions seems not to be met.
This is how I use the triggers. Simply an if/else block.
<DataTemplate.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsDownloading}" Value="False"/>
<Condition Binding="{Binding downloaded}" Value="True"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter TargetName="ButtonDownload" Property="Visibility" Value="1"/>
<Setter TargetName="DownloadProgressPanel" Property="Visibility" Value="1"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsDownloading}" Value="True"/>
<Condition Binding="{Binding downloaded}" Value="False"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter TargetName="DownloadProgressPanel" Property="Visibility" Value="0"/>
<Setter TargetName="ButtonDownload" Property="Visibility" Value="1"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsDownloading}" Value="False"/>
<Condition Binding="{Binding downloaded}" Value="False"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter TargetName="DownloadProgressPanel" Property="Visibility" Value="1"/>
<Setter TargetName="ButtonDownload" Property="Visibility" Value="0"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
<DataTrigger Binding="{Binding favouriteListType}" Value="8">
<Setter TargetName="URLButtonsPanel" Property="Visibility" Value="Visible"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>

DataTrigger setter will not update property. Why?

XAML :
<RadioButton x:Name="RadioButtonA">
<RadioButton.Style>
<Style TargetType="RadioButton">
<Setter Property="IsChecked" Value="{Binding Path=RadioAValue}" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=CheckBoxA, Path=IsChecked}" Value="True">
<Setter Property="IsChecked" Value="True"/>
</DataTrigger>
</Style.Triggers>
</Style>
</RadioButton.Style>
</RadioButton>
C# Code behind
public bool RadioAValue
{
get
{
...
}
set
{
...
}
}
set section of RadioAvalue will not be called when CheckBoxA is checked.
Any reason why?
Problem in your code
You are setting the binding in Style Setter
<Setter Property="IsChecked" Value="{Binding Path=RadioAValue}" />
and on clicking the checkbox you have overwriting the Binding with the value False. Now there is no more Bindings over the element and it wont call the set anymore.
Also, if you try to bind it over the RadioButton itself instead of setters that will take more precedence and your Triggers won't work there.
Solution
I would recommend you to have Command binding over the Checkbox and update the value RadioAValue from your ViewModel
If you want conditional setter use MultiBinding, right now you block binding with already setted value
<Setter Property="IsChecked" Value="{Binding Path=RadioAValue}" />
Must be something like this (didn't test thought):
<RadioButton x:Name="YouRadioButton">
<RadioButton.Style>
<Style TargetType="RadioButton">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding ElementName=CheckBoxA, Path=IsChecked}" Value="True"/>
<Condition Binding="{Binding RadioAValue}" Value="True"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="IsChecked" Value="True"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
<DataTrigger Binding="{Binding ElementName=CheckBoxA, Path=IsChecked}" Value="False">
<Setter Property="IsChecked" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</RadioButton.Style>
</RadioButton>
<CheckBox x:Name="CheckBoxA"/>

How to change Background of datagridcell based on multiple condition WPF?

I have datagrid with some conditional row. And I want if I select particular row in datagrid, The selected color will change based on my record value.
Suppose I have record of Students with IsDropOut Flag.
And then If I click selected record of student, Selected row will change color according to IsDropOut value. If it is true it will set selected row background to red and if IsDropOut is false it will change selected row background to green.
Maybe with like this
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=DataGridCell.IsSelected}" Value="True" />
<Condition Binding="{Binding Path=IsDropOut}" Value="true" />
</MultiDataTrigger.Conditions>
<Setter Property="Background" Value="red" />
</MultiDataTrigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
But that's code is not work. So how to do it? Anyone has suggestion?
Finally I solve this.. Thanks for the idea..
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=IsDropOut}" Value="True" />
<Condition Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource Self}}" Value="True" />
</MultiDataTrigger.Conditions>
<Setter Property="Background" Value="Red" />
<Setter Property="Foreground" Value="White" />
</MultiDataTrigger>
Try this :
<Style TargetType="DataGridCell">
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="True" />
<Condition Property="IsDropOut" Value="true" />
</MultiTrigger.Conditions>
<Setter Property="Background" Value="Red" />
</MultiTrigger>
</Style.Triggers>
</Style>

Simplification of this XAML code possible? (MultiDataTrigger, DependencyProperty)

finally I got my custom button almost act like I want it to act.
The problem is the code :D (IsChecked is a DependencyProperty)
<ControlTemplate.Triggers>
<!-- EventTriggers for LMBUp/LMBDown/MouseEnter/MouseLeave -->
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}" Value="True"/>
<Condition Binding="{Binding RelativeSource={RelativeSource Mode=Self}, Path=IsChecked}" Value="False"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource MouseEnter}"/>
</MultiDataTrigger.EnterActions>
<MultiDataTrigger.ExitActions>
<BeginStoryboard Storyboard="{StaticResource MouseLeave}"/>
</MultiDataTrigger.ExitActions>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}" Value="True"/>
<Condition Binding="{Binding RelativeSource={RelativeSource Mode=Self}, Path=IsChecked}" Value="True"/>
</MultiDataTrigger.Conditions>
<Setter TargetName="LayoutRoot" Property="Background" Value="Red"/>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}" Value="False"/>
<Condition Binding="{Binding RelativeSource={RelativeSource Mode=Self}, Path=IsChecked}" Value="True"/>
</MultiDataTrigger.Conditions>
<Setter TargetName="LayoutRoot" Property="Background" Value="Red"/>
</MultiDataTrigger>
</ControlTemplate.Triggers>
I think it is a bit "dirty" and it doesn't fully act like expected.
Everytime the user clicks on the button IsChecked gets switched from true to false or vice versa.
Now if the following happens
IsChecked == true
User clicks to switch IsChecked to false
All the time the mouse is ON the button
then I would expect that the button becomes $MouseOverColor$ instead of $ButtonNormalBackground$ because of the first MultiDataTrigger.
My questions are if it is possible to simplify the code and to correct the last problem?
Thanks in advance!
You probably have 'value resolution strategy' issue. DependencyProperty has a set strategy of how to resolve the value, see here.
If your animations set the value of Background of LayoutRoot then other setters will not have affect until you stop the animation (in this case the setters are treated as "Local Value").
You can use <StopStoryboard> element in EnterActions of second and third triggers. Note that this will write a warning in the output window if the storyboard is already stopped when the trigger was activated.
--Alternatively--
You can use FillBehavior="Stop" in your storyboard.

Categories