WPF Binding DataTrigger To A Different Property - c#

I have a Teleric RadGrid View like this that's bound to a property called Load:
<telerik:RadGridView x:Name="myRadGridView"
ItemsSource="{Binding Load}">
I have a DataTrigger for that same grid that I want to bind to a property called checkColor which is in the same class as the RadGridView's Load property. I think this isn't working because both properties are in the same class? What would be the correct syntax?
<telerik:RadGridView.Resources>
<Style TargetType="telerik:GridViewRow">
<Style.Triggers>
<DataTrigger Binding="{Binding checkColor}" Value="true">
<DataTrigger.Setters>
<Setter Property="Background" Value="Blue" />
</DataTrigger.Setters>
</DataTrigger>
</Style.Triggers>
</Style>
</telerik:RadGridView.Resources>

P.s. revisited this and finally found the real solution.
1) Added an item to the Window pointing at the class I wanted to reference.
xmlns:local="clr-namespace:MyClass"
2) Created a static resource to it on a parent component:
<DockPanel.Resources>
<local:Changes x:Key="MyViewModel"/>
</DockPanel.Resources>
3) Set my setter binding to point at it:
<Setter Property="Background" Value="{Binding Source={StaticResource MyViewModel}, Path=checkColor}"/>
Old "Solution":
Ended up solving the problem by putting the data the checkColor function was going to return into a new column in the DataTable that the RadGridView is bound to. Since columns are part of the RadGridView's binding scope I could bind it to the DataTrigger like this:
<telerik:RadGridView.Resources>
<Style TargetType="telerik:GridViewRow">
<Style.Triggers>
<DataTrigger Binding="{Binding checkColorDataColumn}" Value="1">
<DataTrigger.Setters>
<Setter Property="Background" Value="Blue" />
</DataTrigger.Setters>
</Style.Triggers>
</Style>
</telerik:RadGridView.Resources>

Related

WPF After a data trigger is in use (sealed), it cannot be modified

I have no idea what is wrong, and how I am supposed to solve the error. Strangely enough, the data triggers work fine.
<Style TargetType="Border">
<Setter Property="Background" Value="{StaticResource HeaderBackgroundBrush}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding State}" Value="{StaticResource ErrorState}">
<Setter Property="Background" Value="OrangeRed"/>
</DataTrigger>
<DataTrigger Binding="{Binding State}" Value="{StaticResource ProductionState}">
<Setter Property="Background" Value="Green"/>
</DataTrigger>
</Style.Triggers>
</Style>
ProductionState and Error states are enum values referenced in XAML:
<machineControl:MachineControllerState x:Key="ErrorState">Error</machineControl:MachineControllerState>
<machineControl:MachineControllerState x:Key="ProductionState">Production</machineControl:MachineControllerState>
The State binding references to the view model which is "a normal" property which supports IPropertyChanged (from mvvm lights lib)
public MachineControllerState State
{
get => state;
set { Set(() => State, ref state, value); }
}
visual studio shows the error in error list:
After a data trigger is in use (sealed), it cannot be modified
Update: to be clear, the solution compiles fine, and runtime everything works as expected.
You can refer your enum directly from your codebehind. Something like:
{x:Static namespacename:EnumName.EnumValue}
Reference:
How can I use enum types in XAML?

WPF control not returning in previous state after triggering

XAML
<utility:InvalidNotification x:Name="InvalidNotificationControl"/>
<Button Content="Clean AppV Cache" Click="Button_Click">
<Button.Style>
<Style TargetType="Button">
<Setter Property="IsEnabled" Value="True"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=InvalidNotificationControl, Path=Visibility}" Value="Visible">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
NOTE
InvalidNotification is a custom UserControl
Now, the DataTrigger works fine initially and disable the button since the Usercontrol is visible.
The problem is when I collapse the Usercontrol based on another condition the button stays disable. I found this related answer which states that The properties changed by triggers are automatically reset to their previous value when the triggered condition is no longer satisfied. which is not my case. Why is that ?
EDIT
Thanks to #mm8 which led me to the solution. So if ever you're trying to bind a control on a UserControl's content (inner TextBlock in my case), just add a second trigger at the bottom of your Usercontrol like so,
<UserControl.Style>
<Style TargetType="UserControl">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=Notification, Path=Visibility}" Value="Visible">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Style>
where notification would be the name of my TextBlock
Your example works provided that you toggle/set the Visibility property of the InvalidNotification control itself, since it is this property that you bind to.
If you set the Visibility property of some element within the InvalidNotification control, you need to bind to this specific element.
You can't do this using an ElementName binding though because the Button and any element defined in the InvalidNotification control don't belong to the same namescope.

How does this ItemsContainerStyle know about ItemsControl.AlternationIndex

I've been reading through WPF Unleashed and something has confused me about styles.
<Style TargetType="{x:Type Control}" x:Key="altStyle">
<Setter Property="Background" Value="Green"></Setter>
<Setter Property="Foreground" Value="White" ></Setter>
<Style.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Background" Value="White"></Setter>
<Setter Property="Foreground" Value="Black" ></Setter>
</Trigger>
</Style.Triggers>
</Style>
So I have a style here which can be applied to anything that derives from control. Assuming that's how the TargetType works. The confusing part for me is how it understands what ItemsControl.AlternationIndex is. I'm defining a style for a control, which is higher up the inheritance chain than ItemsControl. It's seems to break the rules of inheritance.
I then have a simple datagrid which uses this style as its ItemsContainerStyle:
<local:MyGrid AlternationCount="2" ItemsSource="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataContext.Source}" Grid.Row="3" ItemContainerStyle="{StaticResource altStyle}"></local:MyGrid>
(MyGrid derives from DataGrid)
I'm assuming here that the style is applied to each DataRow in the grid, but how on earth is able to resolve this ItemsControl.AlternationIndex as this certainly does not apply to a DataRow does it? and just for clarity on how it looks:
So the question is. How does a style that applies to a datagrid row manage to resolve a property called ItemsControl.AlternationIndex
As an attached property the AlternationIndex can be set on any dependency object and can potentially be inherited. When the style queries the rows it will find that the attached property has been set on them by the creating ItemsControl (the grid control).

How to apply style to treeviewitem if the datacontext is an object of Type T

Is there a way to do this, or do I have to create an IsSelectedProperty on the ViewModel and Bind to that instead?
I would like to be able to do something like Source={Binding RelativeAncestor ListViewItem}
but instead there is only this property sourcename which I can use to set triggers based off of the items in the datatemplate if I name them using x:Name
<HierarchicalDataTemplate.Triggers>
<Trigger SourceName="" Property="IsSelected" Value="True">
<Setter TargetName="bdr" Property="Foreground" Value="White"/>
<Setter TargetName="bdr" Property="Foreground" Value="Red"/>
</Trigger>
</HierarchicalDataTemplate.Triggers>
Looking back, I realized that yesterday I made a very confusing post. Also, considering how hard I find it to even interpret people's comments to my questions, I should probably give more detail.
I know that in wpf you can set triggers based on the control by setting a style for the target control type.
In addition you also have data triggers that can trigger off of properties in the datacontext. What I was hoping was that there was a way to use triggers, or datatriggers to set a property when the datacontext is an object of a specific type.
is this possible? If not, I will just accept the provided answer as applicable in my situation, but since this will require me to add a property to my viewmodel, it seemed reasonable to check if there was a way to just check item type rather than having to check the actual property.
I would suggest that you bind the IsSelected property in your view model, but that's just me.
I'm not sure how complex your HierarchicalDataTemplate is, or if some items need to have their Foreground changed, and some don't; but I'm going to assume you want to update the item that is selected throughout the entire TreeView (if that's what this is for).
If that is the case, just add DataTriggers to the Style of the TreeViewItem:
<Style TargetType="TreeViewItem">
<Setter Property="IsSelected"
Value="{Binding IsSelected, Mode=TwoWay}" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected}" Value="True">
<Setter Property="Foreground"
Value="Red" />
</DataTrigger>
<DataTrigger Binding="{Binding IsSelected}"
Value="False">
<Setter Property="Foreground"
Value="Black" />
</DataTrigger>
</Style.Triggers>
</Style>
Note that you don't need to bind the IsSelected parameter if you don't want to, its just there because it's in my code.

Color coding individual rows in a DataGrid based on row contents

I have inherited a .NET 2.0 c# project that does the following:
Executes a SQL Query
Binds the SQL result to a DataGrid
I have found a fair bit of information on how to achieve this in a DataGridView, however this does not seem applicable to a DataGrid (missing methods/Event handlers that DataGridViews have).
What I am trying to achieve, is based on the results of a column set the background color of the column to red (for example).
Does anyone have any suggestions, is is converting to a DataGridView going to be the only realistic option (I would like to avoid this if possible!)
You can use multiple DataTriggers in your DataGrid Style.
<DataGrid Grid.Row="1" AutoGenerateColumns="True" VerticalAlignment="Top" ItemsSource="{Binding Items}">
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Style.Triggers>
<DataTrigger Binding="{Binding ItemIndex}" Value="True">
<Setter Property="Background" Value="Red"/>
</DataTrigger>
<DataTrigger Binding="{Binding ItemIndex}" Value="False">
<Setter Property="Background" Value="Blue"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
...
...
</DataGrid>
More info on DataTriggers here: http://msdn.microsoft.com/en-us/library/system.windows.datatrigger.aspx

Categories

Resources