Data Trigger won't trigger background change - wpf

I have a TouchListBoxItem and i'm trying to change the background of per "box" when a certain data is "false"
I want to change the background color of certain items in the touchlistbox and these items has a boolean data that should trigger if it should change background
<c:TouchListBox.ItemContainerStyle>
<Style
TargetType="ListBoxItem"
BasedOn="{StaticResource noMouseOverListBoxItemStyle}">
<Setter
Property="FocusVisualStyle"
Value="{StaticResource FocusVisualStyle}" />
<Style.Triggers>
<DataTrigger
Binding="{Binding IsGroupingItem, RelativeSource={RelativeSource FindAncestor, AncestorType=ListBoxItem}}"
Value="False">
<Setter
Property="Background"
Value="{StaticResource ItemBackgroundColorBrush}" />
</DataTrigger>
</Style.Triggers>
</Style>
</c:TouchListBox.ItemContainerStyle>
Added the Style.Triggers and if the IsGroupingItem is False then it should change the Background to ItemBackgroundColorBrush.

The expression
{Binding IsGroupingItem, RelativeSource={RelativeSource AncestorType=ListBoxItem}}
expects an IsGroupingItem property in the ListBoxItem class, which it doesn't have.
Bind to a property of the actual item object by
Binding="{Binding IsGroupingItem}"
Also make sure that IsGroupingItem is actually a public property, not a field, and that it fires the PropertyChanged event of the INotifyPropertyChanged interface.

Related

DataGrid Row Background Based On Cell Contains Value WPF

Is it possible to change the background colour of DataGrid Row depending on the content of the cell? For example, the cell value contains "!"
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Style.Triggers>
<DataTrigger Binding="{Binding Opis}" Value<!-- contains-->="!">
<Setter Property="Background" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
There is no Contains method defined in XAML so you will have to either use a converter or bind to a boolean property that uses the string.Contains method to determine whether the current value of Opis contains a specific string.
So if you add another property to the class where the Opis property is defined, you could bind to this one instead of binding to Opis, e.g.:
public bool Contains => !string.IsNullOrEmpty(Opis) && Opis.Contains("!");
XAML:
<DataTrigger Binding="{Binding Contains}" Value="True">
<Setter Property="Background" Value="Red"/>
</DataTrigger>

Can not change template of ContentControl from style's datatrigger - datatrigger not firing

Hello WPF aficionados,
I have a content control inside a user control that sets it data context to the selected item of a listview inside the same usercontrol. The selected item property on the view model is called Selection.
Here is the content control's declaration:
<ContentControl DataContext="{Binding Selection}">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Setter Property="Template" Value="{StaticResource JobSnapShotProgDetail}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding bTandM}" Value="1">
<Setter Property="Template" Value="{StaticResource JobSnapShotProgDetail}"/>
</DataTrigger>
<DataTrigger Binding="{Binding bTandM}" Value="0">
<Setter Property="Template" Value="{StaticResource JobSnapShotTM_Detail}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
The Templates are defined as ControlTemplates in another resource file like:
<ControlTemplate x:Key="JobSnapShotProgDetail" >
...
</ControlTemplate >
<ControlTemplate x:Key="JobSnapShotTM_Detail" >
...
</ControlTemplate >
The binding works great meaning that the template's fields all display the correct data from the Selection object.
My Problem:
I want the content control to use one of two different control templates based on the value of the Selection's bTandM property.
What happens now:
When I change the selection of the listview, which changes the Selection object, the template IS NOT being changed based on the value of the Selection's bTandM property (a sql server bit data type). Yes the Selection object implements iNotifyPropertyChanged, and the ControlTemplate's fields that bind to the Selection's properties all display the correct data without any binding errors in the output window.
What I Tried:
It seems like the datatrigger is not getting "HIT" by the code. I tried to break the datatrigger by adding foo instead of a number which should have not been able to convert, but no error is generated. ie:
<DataTrigger Binding="{Binding bTandM}" Value="foo">
This leads me to believe that the trigger is not firing for some reason.
Question:
Can someone help me figure out why this data trigger has no effect.
Thanks in advance
JK
EDIT 1:
I tried to use a technique found HERE, but it also does not work. THe data triggers are not getting fired.
New attempt using DataTemplate with DataTriggers that target a contentcontrol's template property:
<ItemsControl ItemsSource="{Binding SelectionCollection}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentControl x:Name="DetailControl" Template="{DynamicResource JobSnapShotProgDetail}" />
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding bTandM}" Value="False">
<Setter TargetName="DetailControl" Property="Template" Value="{DynamicResource JobSnapShotProgDetail}" />
</DataTrigger>
<DataTrigger Binding="{Binding bTandM}" Value="1">
<Setter TargetName="DetailControl" Property="Template" Value="{DynamicResource JobSnapShotTM_Detail}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Again, the template loads fine and the properties are display correctly for the initial template set in the style setter, but the templates do not change based on the object's bTandM boolean property.
Okay, so this turned out to be an issue with NotifyPropertyChanged.
The selection property of my viewmodel does implement INPC but the problem was that the underlying class type (vw_Job_Snapshot which is a mapped entity from a sql server view) of selection did not.
I had to implement iNPC in the underlying class and then in my viewmodel use the Property Setter for the Selection Property to also notify the specific bTandM property change like so:
Public Property Selection As vw_Job_Snapshot
Get
Return Me._Selection
End Get
Set(ByVal value As vw_Job_Snapshot)
Me._Selection = value
''Notify of specific property changed
value.OnPropertyChanged("bTandM")
_Selection = value
RaisePropertyChanged(JobSnapshotSelectedPropertyName)
End Set
End Property
After this the following code in my view worked perfectly:
<ContentControl DataContext="{Binding Selection}">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Setter Property="Template" Value="{DynamicResource JobSnapShotTM_Detail}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding bTandM}" Value="False">
<Setter Property="Template" Value="{DynamicResource JobSnapShotProgDetail}"/>
</DataTrigger>
<DataTrigger Binding="{Binding bTandM}" Value="True">
<Setter Property="Template" Value="{DynamicResource JobSnapShotTM_Detail}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
Thanks to everyone who helped
Try using a DataTemplateSelector instead.
Your selector would look something like this (I'm assuming your class is called JobSnapShot):
public class JobSnapShotDataTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
FrameworkElement element = container as FrameworkElement;
if (element != null && item != null && item is JobSnapShot)
{
JobSnapShot jobSnapShot = item as JobSnapShot;
if (jobSnapShot.bTandM == 1)
return
element.FindResource("JobSnapShotProgDetail") as DataTemplate;
else
return
element.FindResource("JobSnapShotTM_Detail") as DataTemplate;
}
return null;
}
}
XAML:
<Window.Resources>
<local:JobSnapShotDataTemplateSelector x:Key="myDataTemplateSelector"/>
</Window.Resources>
<ContentControl ItemTemplateSelector="{StaticResource myDataTemplateSelector}" .... />

How to set a viewmodel property if a listbox item selected?

I have a listbox...and it is bound to list of items of type (class) "A". Class "A" has a boolean property "IsCurrentViewActive". This is false by default. When user select an item in listbox....i need to set the "IsCurrentViewActive" property of corresponding item to TRUE.
I tried the below code in my listbox...but it is not working..Any help would be appreciated.
<Style x:Key="ListBoxItemTabStyle2Extended" TargetType="{x:Type ListBoxItem}" >
<Setter Property="IsSelected" Value="{Binding Path=IsCurrentViewActive, Mode=TwoWay}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}}" Value="True">
<Setter Property="IsSelected" Value="{Binding Path=IsCurrentViewActive, Mode=TwoWay}"/>
</DataTrigger>
</Style.Triggers>
</Style>
EDIT : Can we do this way or Do I need to use attached property ?
The above XAML worked fine for me actually. I think it's just a matter of getting the context right. I have created a sample that you can download where this works fine. I think the difference might be that in my version, I store the style in ListBox's parent control's resources. I don't think you can store them in the ListBox's resources.
https://www.dropbox.com/s/s64kp9p0b2w1imk/ListBoxMenu.7z?dl=0

Trigger for IsChecked does not Trigger

I want to change the Icon of a ToggleButton (Content of Fluent RibbonBar) Depending on it's IsChecked Property. Now I have written the following style snippet:
<Fluent:ToggleButton.Style>
<Style BasedOn="{StaticResource RibbonButtonStyle}" TargetType="{x:Type Fluent:ToggleButton}">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Fluent:ToggleButton}}, Path=IsChecked}" Value="False">
<Setter Property="Icon" Value="{StaticResource ResourceKey=Style.Images.Pined}"/>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Fluent:ToggleButton}}, Path=IsChecked}" Value="True">
<Setter Property="Icon" Value="{StaticResource ResourceKey=Style.Images.Unpined}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Fluent:ToggleButton.Style>
The problem is that the Trigger doesn't load the Image well. The problem is not, that IsChecked doesn't actualize itself, I've already tested this. And also I don't set the icon property anywhere else. The image resources also works fine if I use them otherwhere.
Information for Rebuild: I've put the ToggleButton into the Backstage as the DataTemplate of a RibbonListBox placed in a BackstageTabItem.
Since this is a style for togglebutton you don't need a findancestor binding - you would use self. And actually since IsChecked is a DP you can just use a trigger - eg <Trigger Property="IsChecked" Value="False">
You absolutely need to remove the Icon property from the control declaration as it will override everything a style tries to do due to precedence.
But those DataTriggers will not work, the binding will look for an ancestor, itself excluded, so you must change them as well as already pointed out by AndrewS. Only if both conditions are met you have a chance of getting this to work (there may be even additional interferences though).

Updating style on runtime in wpf

I have a style for a ItemContainer that is based on the Item being contained (With a StyleSelector). It works fine. However on runtime the property might be changed but the style isn't updated instantly.
Is there anyway for me to get it to update as soon as the changes are saved?
Use a DataTrigger and a Converter which returns the Type of an object
For example,
<Style.Triggers>
<DataTrigger Binding="{Binding Converter=ObjectToTypeConverter}"
Value="{x:Type local:Person}">
<Setter Property="ItemTemplate" Value="{Binding PersonTemplate}" />
</DataTrigger>
<DataTrigger Binding="{Binding Converter=ObjectToTypeConverter}"
Value="{x:Type local:Business}">
<Setter Property="ItemTemplate" Value="{Binding BusinessTemplate}" />
</DataTrigger>
</Style.Triggers>
Use binding. Then you will need to implement INotifyPropertyChanged. The value you are setting should be a property and at the end of the setter, raise the property changed event.
If you give an example of your XAML, I can write it out for you.

Resources