Make xaml datatrigger work in c# code - c#

I am new to xaml, i have following code below, my question is how can i call InvalidForeground from c# code to change the color of checkbox text?
<ControlTemplate x:Key="ItemTemplate"
TargetType="ListViewItem">
<StackPanel Orientation="Horizontal">
<CheckBox x:Name="CkBoxVisual">
<CheckBox.IsChecked>
<Binding Path="IsSelected"
Mode="TwoWay">
<Binding.RelativeSource>
<RelativeSource Mode="TemplatedParent" />
</Binding.RelativeSource>
</Binding>
</CheckBox.IsChecked>
<DataTrigger Binding="{Binding InvalidForeground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}" Value="true">
<Setter TargetName="CkBoxVisual" Property="Foreground" Value="Red"/>
</DataTrigger>
</CheckBox>
<ContentPresenter />
</StackPanel>
</ControlTemplate>

In your code, you are not calling anything. In it, you're hoping a change of dependency property..
But a control of type Window does not have a dependency property with the name: "InvalidForeground".
This trigger will never be triggered.
What is your goal, change a property or be notified of a change (trigger)?
Edit: There are a number of rules you must follow:
1) The control referenced in Binding property from DataTrigger (RelativeSource):
Binding="{Binding Path=InvalidForeground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"
Must have a dependency property called "InvalidForeground", which works correctly, based on this, will not work:
{x:Type Window}
its type must be declared, will work, for example:
{x:Type my:ControlName}
2) A property changed by a Trigger or DataTrigger can never be explicitly stated, for example. Will not work:
<TextBlock Text="{Binding Any}" Foreground="#FFCCCCCC">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=TabItem, Mode=FindAncestor}, Path=IsSelected}" Value="True">
<Setter Property="Foreground" Value="Black"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
Will work:
<TextBlock Text="{Binding Any}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="#FFCCCCCC"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=TabItem, Mode=FindAncestor}, Path=IsSelected}" Value="True">
<Setter Property="Foreground" Value="Black"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
3) Check the operation of Bindings using RelativeSource they have some peculiarities (you should know a little about the visual tree of WPF).
http://msdn.microsoft.com/en-us/library/ms743599.aspx
4) You should check that the binding is working properly and can follow these steps:
http://www.codeproject.com/Articles/244107/Debugging-WPF-data-bindings

Related

WPF binding not applied - why does it happen

I wanted to update a stringformat of my binding via a datatrigger. So I thought of just doing this:
<TextBlock Text="{Binding Foo.Name}" Margin="3">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Text" Value="{Binding Path=., StringFormat='Start {0}'}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Foo.IsEnabled}" Value="True">
<Setter Property="Text" Value="{Binding Path=., StringFormat='Stop {0}'}" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
now this just shows the value of Foo.Name and not with the string format applied('start'/'stop' string).
I've modified the code, to get it working. This is the working code:
<TextBlock Margin="3">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Text" Value="{Binding Foo.Name, StringFormat='Start {0}'}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Foo.IsEnabled}" Value="True">
<Setter Property="Text" Value="{Binding Foo.Name, StringFormat='Stop {0}'}" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
Now i'm looking for the reason why the first piece of code doesn't work and why the second piece of code works.
I've seen similar behavior in DataTemplates where I could not set or alter a property value via a Setter in a DataTrigger because the property was already set directly via the property on the object itself. Only when I removed the property from the object itself and set it as a style it worked.
Or is this just a limitation in WPF?
I wouldn't call it a limitation, it's documented. Dependency properties have a value precedence. https://msdn.microsoft.com/en-us/library/ms743230(v=vs.110).aspx

DataTrigger for IconTemplate in RadWindow

I have a WPF application and I use Telerik.
I'm trying to set the Icon Template so that it has a default value and only on a certain condition will it bind the image source:
<telerik:RadWindow.Resources>
<Style x:Key="CustomIconStyle" TargetType="Image">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsConditionMet, ElementName=MyWindow, UpdateSourceTrigger=PropertyChanged}" Value="True">
<Setter Property="Source" Value="{Binding Path=IconImageSource, ElementName=MyWindow, UpdateSourceTrigger=PropertyChanged}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</telerik:RadWindow.Resources>
<telerik:RadWindow.IconTemplate>
<DataTemplate>
<Image Style="{StaticResource CustomIconStyle}" Source="/MyAssembly;Component/Resources/myIcon.ico" Height="16" Margin="0,0,5,0"/>
</DataTemplate>
</telerik:RadWindow.IconTemplate>
For some reason it always show the default icon.
I would also like to mention that I did implement the property changed - and I copied the same style just to a control inside the window and not in the template and it worked - so the problem isn't with the property changed
Any ideas?
You can use Triggers like that :
<telerik:RadWindow.Resources>
<Style TargetType="Image" x:Key="Style1">
<Setter Property="Source" Value="default.ico"/>
<Style.Triggers>
<DataTrigger Binding="{Binding MyCondition}" Value="true">
<Setter Property="Source" Value="custom.ico"/>
</DataTrigger>
</Style.Triggers>
</Style>
</telerik:RadWindow.Resources>
<telerik:RadWindow.IconTemplate>
<DataTemplate>
<Image Style="{StaticResource Style1}" Height="16" Margin="0,0,5,0"/>
</DataTemplate>
</telerik:RadWindow.IconTemplate>
So the problem was that once the RadWindow was loaded it didn't change the Icon.
The solution:
<telerik:RadWindow.IconTemplate>
<DataTemplate>
<Image Height="16" Margin="0,0,5,0">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Setter Property="Source" Value="/MyAssembly;Component/Resources/myIcon.ico" />
<Style.Triggers>
<DataTrigger Value="True" Binding="{Binding Path=IsConditionMet, ElementName=MyWindow}">
<Setter Property="Source" Value="{Binding Path=IconImageSource, ElementName=MyWindow}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</DataTemplate>
</telerik:RadWindow.IconTemplate>
But the trick is to give the correct value of IsConditionMet in the windows constructor before the load.
Thanks for the help everyone.

How to Bind an another Control on the Setter Value Property by using a Trigger?

i've a little Problem with the Databinding in WPF an hope you can help me.
I want to bind the SelectedDate Parameter of a DatePicker on a TextBlock, but only when a CheckBox is checked. The CheckBox and the TextBlock are in a DataView, the DatePicker is outside.
In the Moment i try to use it with a Trigger an set the Binding in the Value-Property in the Setter Part.
<TextBlock Text="">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsChecked}" Value="True">
<Setter Property="Text" Value="{Binding ElementName=StandartPitBis, Path=SelectedDate, StringFormat='dd.MM.yyyy'}" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
But this will not works. Has anywone a Tipp what i can do?
Here is the Code-Parts there i'm using:
Inside the GridView
The CheckBox
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox Content="" x:Name="check_Anlage" IsChecked="{Binding Path=IsChecked}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
The TextBlock
<TextBlock Text="">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsChecked}" Value="True">
<Setter Property="Text" Value="{Binding ElementName=StandartPitBis, Path=SelectedDate, StringFormat='dd.MM.yyyy'}" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
Outside the GridView
The DatePicker
<DatePicker Grid.Column="1" Margin="0,5,0,5" SelectedDate="{x:Static sys:DateTime.Now}" x:Name="StandartPitVon" />
What i want to make is, that the SelectedDate from the DatePicker is shown in the TextBlock, but only when the CheckBox is Checked.
Thanks a lot
So. I've found the Problem. The Problem is, when a Property is set in the Object self, then it can't be overridet. When you need a Default-Value and a Trigger, then you must define the Default-Value in the Style too.
Example:
<TextBlock>
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Text" Value="{x:Null}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsChecked}" Value="True">
<Setter Property="Text" Value="{Binding ElementName=StandartPitVon, Path=SelectedDate, StringFormat='dd.MM.yyyy'}" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>

How to bind with a relative source that is Ancestor and Self?

I have the following code:
<ItemsControl ItemsSource="{Binding MyDictionary}" >
<Image Width="16">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding Value}" Value="False">
<Setter Property="Source" Value="{Binding RelativeSource =
{RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}},
Path=DataContext.SecDic}"/>
</DataTrigger>
<DataTrigger Binding="{Binding Value}" Value="True">
<Setter Property="Source" Value="{Binding RelativeSource =
{RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}},
Path=DataContext.ThirdDic}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</ItemsControl>
MyDictionary - Is a dictionary that the key is of type enum
Now This binding works if I change the SecDic and ThirdDic from dictionaries to BitmapImages. But I want that for each key (enum) in MyDictionary there will be a different True/False image.
So I tried to write:
<Setter Property="Source" Value="{Binding Path=DataContext.SecDic[Key],
RelativeSource={AncestorType={x:ItemsControl}}}"/>
But it doesn't work since the "Key" belongs to the data context of the image (of MyDictionary) and I changed the relative source to be the items control so there is no "Key".
Any suggestions?
What I did to solve this is a multibinding + a custom multibinding converter.
There was one binding for the dictionary and one for the key.

MenuItem.Icon not greyed out with DataTrigger

I try to show a different image as menuitem.icon if the menuitem is disabled (just a greyed out version). This is what I tried:
<tk:DataGrid.ContextMenu>
<ContextMenu>
<MenuItem Header="_Divorce" Command="{Binding Path=DivorceCommand}">
<MenuItem.Icon>
<Image>
<Image.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsEnabled, RelativeSource={RelativeSource FindAncestor, AncestorType=MenuItem, AncestorLevel=3}}" Value="true">
<Setter Property="Image.Source" Value="eraser.ico" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=IsEnabled, RelativeSource={RelativeSource FindAncestor, AncestorType=MenuItem, AncestorLevel=3}}" Value="false"
<Setter Property="Image.Source" Value="eraser_grey.ico" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</tk:DataGrid.ContextMenu>
</tk:DataGrid>
Error message:
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.MenuItem', AncestorLevel='1''. BindingExpression:Path=IsEnabled; DataItem=null; target element is 'Image' (Name=''); target property is 'NoTarget' (type 'Object')
What is wrong with my current XAML datatrigger binding?
I appreciate any help!
You could try the following:
Add a Trigger like CubaLibre mentioned
But instead of using a target name, which will not work. Use the following.
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Image">
<Setter.Value>
<Image Source="eraser_grey.ico"/>
</Setter.Value>
</Setter>
</Trigger>
if that will not work (sorry can't test it for myself at the moment). You could also do it the hard way:
Create a Style for menuitem, you can just completely copy the original style
Now in the control template, of the desired role template, you just add under ControlTemplate.Triggers. Your trigger like
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Source" Value="eraser_grey.ico"/>
</Trigger>
to make it a little bit cleaner. I would add a service class, which contains an attached property named "DisabledIcon" or similiar and use that as an value, instead the hard coded one.
Unfortunately changing the whole style is the only working way i can think of right now.
[Edit]
Ok after some further investigation, here is a solution that works fine, even though i'm not happy with it because it is quiet ugly :( But sorry i have no better idea at the moment.
<MenuItem Header="_Divorce" Command="...">
<MenuItem.Icon>
<ContentControl>
<ContentControl.ContentTemplate>
<DataTemplate>
<Image x:Name="iconImage" Source="arrowDown.png"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsEnabled, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type MenuItem}}}" Value="False">
<Setter TargetName="iconImage" Property="Source" Value="close.png"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
</MenuItem.Icon>
</MenuItem>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Source" TargetName="Image" Value="eraser_grey.ico"/>
</Trigger>
Does it work when you try to do so

Categories