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).
Related
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.
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>
Is there a way (using data binding or simply xaml) to set the background of all elements in a view to one color, and all text to another?
I know I can edit each element in the view one by one, but I I'd like to see if this is possible with settings at a global level. Kind of like how everything by default is set to black on white.
I guess what I'm asking is if there is a feature/setting of a WPF application that offers what I'm looking for, and/or what I should search to find an answer online.
My project isn't using anything but what visual studio offers when you create a WPF project, so I can't use a prism or mvvm light approach.
Thanks in advance for your answer!
Globally...or simply XAML...
if there is a feature/setting of a WPF application that offers what I'm looking for
In Application Resource add style like this:
<Style TargetType="Control">
<Setter Property="Background" Value ="Blue"/>
<Setter Property="Foreground" Value ="Red"/>
</Style>
<Style TargetType="TextBlock">
<Setter Property="Background" Value ="Blue"/>
<Setter Property="Foreground" Value ="Red"/>
</Style>
Based on your target element you want to set background.
When you say "the background of all elements in a view" you should be more specific, If by 'element' you mean UIElement then there is no Background property in UIElement. If it means Control then not all UIElementsderive from Control (e.g. TextBlock) and finally if it means every UIElement derived type defined in your view that have a Background property, then you should add different styles for each type without setting the x:key to the YourView.Resources like this:
<Window.Resources>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="Red" />
<Setter Property="Foreground" Value="Blue" />
</Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Red" />
<Setter Property="Foreground" Value="Blue" />
</Style>
...
</Window.Resources>
uses controls collection through which you can control all controls in WPF
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.
I have to apply the following style to my ListViewItem:
<UserControl.Resources>
<local:Look x:Key="ListViewItemLook" Background="Magenta"/>
<Style x:Key="ListViewItemStyle" TargetType="{x:Type ListViewItem}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{Binding Source={DynamicResource ListViewItemLook}, Path=Background}"/>
</Trigger>
</Style.Triggers>
</Style>
But i get an exception, i try to change:
<Setter Property="Background" Value="{Binding Path=Background}"/>
And add to the Style:
<Setter Property="DataContext" Value="{DynamicResource ListViewItemLook}"/>
But is does not work. I can't bind to a StaticResource because I need to set the BackGround property run-time.
What have I to do? Thanks.
If you want both local:Look and the setter to refer to the same color, perform a small refactor:
Pull the color out into a separate SolidColorBrush and make both items refer to it:
<SolidColorBrush x:Key="SelectedListViewItemBackground" Color="Magenta" />
<local:Look x:Key="whatever" Background="{StaticResource SelectedListViewItemBackground}" />
<Setter Property="Background" Value="{StaticResource SelectedListViewItemBackground}" />
If you're trying to do something else, I can't figure out what it is because the question doesn't make sense.
As far as I am aware, DynamicResource extension uses the DependencyProperty mechanism (pretty much like a binding). Therefore you cannot set Source property of a Binding object with DynamicResource because it is not a DependencyProperty.
In addition, if you want to change the Background property of Look but not the Look itself in resources; then setting Look as a static resource to the binding property should not be a problem. Of course Background property of Look class should either trigger a PropertyChanged event or be a DependencyProperty itself.