I've got a small problem, which can be solved for now differently, but I would like to do it via the Style.Trigger of the Border.
My current style for the border looks like this:
<Style x:Key="style_BorderStatus" TargetType="{x:Type Border}">
<Setter Property="Height" Value="75"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Background" Value="#ccc"/>
<Setter Property="IsEnabled" Value="False"/>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="true">
<Setter Property="Background" Value="#9f9"/>
<Setter Property="Cursor" Value="Hand"/>
</Trigger>
</Style.Triggers>
</Style>
My Border looks like this:
<Border Grid.Column="0" Margin="2 2 1 2" Style="{StaticResource style_BorderStatus}">
<TextBlock x:Name="txtStatusKind" Foreground="#999" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="24"/>
</Border>
This works fine so far, even the cursor changes after I set the border to IsEnabled=true.
This means that the trigger style basically works already.
But why is the background setter not affected?
I found my mistake, thanks to #Clemens' hint. I've an initialization method in which I set the color values initially, this also has a higher priority than the styles.
It works now, thanks #all
Related
How can I change one row line color.
<ListView ItemsSource="{Binding ListOfChar}">
<ListView.View>
<GridView>
<GridViewColumn Header="AAAA" DisplayMemberBinding="{Binding Path=AAAA}"/>
<GridViewColumn Header="XXXX" DisplayMemberBinding="{Binding Path=XXXX}"/>
<GridViewColumn Header="BBBB" DisplayMemberBinding="{Binding Path=BBBB}"/>
</GridView>
</ListView.View>
</ListView>
So I have got a listView with 3 column AAAA, XXXX, BBBB. If the column XXXX is equal to 1 then i want color red, if is equal to 2 then blue and if equal to 3 then green in the other case i want keep black
NB : XXXX is a string
Create a style for all your ListViews and then use a DataTrigger to set the foreground color, i.e.:
<ListView.Resources>
<Style TargetType="ListViewItem">
<Setter Property="Foreground" Value="Red" />
<Style.Triggers>
<DataTrigger Binding="{Binding XXXX}" Value="{x:Null}">
<Setter Property="Foreground" Value="Black" />
</DataTrigger>
<DataTrigger Binding="{Binding XXXX}" Value="">
<Setter Property="Foreground" Value="Black" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.Resources>
Note this is a very simple case and therefore one of the very rare cases where I'd say it's ok to just do this in XAML. Once you start adding any real logic then it's better to bind to a property in your view model that you create specifically for this (i.e. public bool IsError.....) and then have your view model update it whenever any of the other properties change.
I have this ListViewItem trigger:
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}" Value="True" />
<Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsSelected}" Value="True" />
</MultiDataTrigger.Conditions>
<Setter Property="Foreground" Value="Gray"/>
<Setter Property="Background" Value="White"/>
<Setter Property="Height" Value="50"/>
</MultiDataTrigger>
When I am selecting my ListViewItem, this item becomes larger so I can show another elements.
Now I want to implement a behavior that after each click on a ListViewItem this item will change from selected to not selected, so after each click my ListViewItem changes its height to 50 and after another click back to 22 (the default size).
I subscribed to an PreviewMouseLeftButtonDown event:
private void listView_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
}
My question is: what do I need to write into this event handler?
You could handle the PreviewMouseLeftButtonDown event for the ListViewItem container:
<ListView x:Name="listView">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<EventSetter Event="PreviewMouseLeftButtonDown" Handler="ListViewItem_PreviewMouseLeftButtonDown" />
<Style.Triggers>
<MultiDataTrigger>
...
</MultiDataTrigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
</ListView>
...something like this:
private void ListViewItem_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
ListViewItem lvi = (ListViewItem)sender;
if (lvi.IsSelected)
{
listView.SelectedItems.Remove(lvi.DataContext);
e.Handled = true;
}
}
I put this EventSetter after my Style (this style is in another file) and got this: 'ResourceDictionary' root element requires a x:Class attribute to support event handlers in the XAML file ...
If you define the ItemContainerStyle in a ResourceDictionary, you need to add a code-behind file to the ResourceDictionary. This is an easy thing to do:
Is it possible to set code behind a resource dictionary in WPF for event handling?
The other option would be to define the Style with the EventSetter inline in your view and base it on the Style with the MultiDataTrigger that you have defined in the ResourceDictionary:
<ListView x:Name="listView">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem" BasedOn="{StaticResource YourOtherStyleInTheResourceDictionary}">
<EventSetter Event="PreviewMouseLeftButtonDown" Handler="ListViewItem_PreviewMouseLeftButtonDown" />
</Style>
</ListView.ItemContainerStyle>
</ListView>
I am trying to change calendar day title foreground color. I am using standard .net 4.0 Datepicker. The calendar is embedded in the Datepicker.
I have the following code in the resource file. but it does not work.
<Style TargetType="{x:Type CalendarItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CalendarItem}">
<ControlTemplate.Resources>
<DataTemplate x:Key="DayTitleTemplate">
<TextBlock
FontWeight="Bold"
FontFamily="Verdana"
FontSize="9.5"
Foreground="Red"
HorizontalAlignment="Center"
Text="{Binding}"
Margin="0,6,0,6"
VerticalAlignment="Center"/>
</DataTemplate>
</ControlTemplate.Resources>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Can anyone help see what I am missing here?
Thanks,
Unfortunately the foreground property is hard-coded in the default control template. The way to change it is to copy-and-modify the template.
<Style x:Key="CalendarItemStyle" TargetType="{x:Type CalendarItem}">
<Setter Property="Margin" Value="0,3,0,3" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CalendarItem}">
<ControlTemplate.Resources>
<DataTemplate x:Key="{x:Static CalendarItem.DayTitleTemplateResourceKey}">
<TextBlock
<!-- Day header color here -->
Foreground="Red"
FontWeight="Bold"
FontSize="9.5"
FontFamily="Verdana"
Margin="0,6,0,6"
Text="{Binding}"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</DataTemplate>
You also might want to use Foreground="{TemplateBinding}", so that way you can modify the color by setting the Foreground property on individual controls.
Take a look at this MSDN Article, it is about customizing the WPF Calendar controls and has this excerpt on the DatePicker Control.
From Link (emphasis mine):
But all the styles and templates you can apply to the standalone Calendar control can also be applied to the Calendar control invoked from the dropdown in DatePicker. The DatePicker control has a property named CalendarStyle of type Style, and the Style object you set to this property can contain setters for any property defined by Calendar, including the CalendarItemStyle, CalendarButtonStyle, and CalendarDayButtonStyle properties.
See this link for the DatePicker Template.
I ran into a strange issue...
It looks like resizing Grid's columns using a GridSplitter disables (or otherwise deactivates) the trigger defined on a Grid's column.
Here's my setup:
A Grid has 3 columns, defined as follows:
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition>
<ColumnDefinition.Style>
<Style>
<Setter Property="ColumnDefinition.Width" Value="Auto"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=OpenItemViewModels.Count}" Value="0">
<Setter Property="ColumnDefinition.Width" Value="0"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ColumnDefinition.Style>
</ColumnDefinition>
<ColumnDefinition>
<ColumnDefinition.Style>
<Style>
<Setter Property="ColumnDefinition.Width" Value="4*"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=OpenItemViewModels.Count}" Value="0">
<Setter Property="ColumnDefinition.Width" Value="0"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ColumnDefinition.Style>
</ColumnDefinition>
</Grid.ColumnDefinitions>
The expectation is that when there are no items that constitute ItemsSource for the control in the third column, 0 width will be assigned to the second and third columns (hosting the GridSplitter and the auxiliary items control, respectively).
This works well as long as I don't touch the Splitter (when all the tabs in the auxiliary control are closed, only the first column remains visible).
The problems start if I move the splitter, thus effectively changing the proportion between columns ##0 and 2. In such scenario, these columns' width is not reset when all the items in the right-hand control are closed.
I suspect this has something to do with the GridSplitter "overruling" my definitions in XAML.
Can someone please confirm / disprove this theory, and suggest how to work around the problem?
I had the same problem for rowdefinition. Gridsplitter will override whatever we give in style or setters. It can be solved using animation (since animation has the highest priority in dependency property value resolution). Do the same for the third column.
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition>
<ColumnDefinition.Style>
<Style>
<Setter Property="ColumnDefinition.Width" Value="Auto" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=OpenItemViewModels.Count}" Value="0">
<DataTrigger.EnterActions>
<BeginStoryboard Name="BeginStoryboard1">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Width">
<ObjectAnimationUsingKeyFrames.KeyFrames>
<DiscreteObjectKeyFrame KeyTime="0:0:0"
Value="{x:Static GridLength.Auto}" />
</ObjectAnimationUsingKeyFrames.KeyFrames>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="BeginStoryboard1" />
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</ColumnDefinition.Style>
</ColumnDefinition>
I came up with a helper class that helps solve the problem of collapsible columns/rows that are also resized with GridSplitter.
public class CollapsibleRowDefinition : RowDefinition
{
public static readonly DependencyProperty IsCollapsedProperty = DependencyProperty.Register(
"IsCollapsed",
typeof(bool),
typeof(CollapsibleRowDefinition),
new FrameworkPropertyMetadata(
false,
(s,e) => { ((CollapsibleRowDefinition) s).IsCollapsed = (bool)e.NewValue; }));
private bool isCollapsed = false;
public CollapsibleRowDefinition()
{
DependencyPropertyDescriptor.FromProperty(RowDefinition.HeightProperty, typeof(RowDefinition)).AddValueChanged(this,
(sender, args) =>
{
if (!this.IsCollapsed)
{
this.ExpandedHeight = this.Height;
}
});
}
public GridLength CollapsedHeight { get; set; }
public GridLength ExpandedHeight { get; set; }
public bool IsCollapsed
{
get { return this.isCollapsed; }
set
{
if (this.isCollapsed != value)
{
this.isCollapsed = value;
this.Height = value ? this.CollapsedHeight : this.ExpandedHeight;
}
}
}
}
markup then goes like this
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="2*"/>
<RowDefinition Height="5"/>
<c:CollapsibleRowDefinition CollapsedHeight="20" ExpandedHeight="*" IsCollapsed="{Binding ElementName=Btn_BottomCollapse, Path=IsChecked}"/>
</Grid.RowDefinitions>
<GridSplitter Grid.Row="2" HorizontalAlignment="Stretch"
IsEnabled="{Binding ElementName=Btn_BottomCollapse, Path=IsChecked}"/>
I had the same problem...
The only thing I was able to work out was something like this:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" x:Name="theColumn"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Expander Grid.Column="0" x:Name="theExpander" Expander.Collapsed="theExpander_Collapsed">
...
</Expander>
<GridSplitter Grid.Column="0" HorizontalAlignment="Right" Width="5">
<GridSplitter.Style>
<Style TargetType="{x:Type GridSplitter}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=theExpander, Path=IsExpanded}" Value="False">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</GridSplitter.Style>
</GridSplitter>
<Grid Grid.Column="1">
...
</Grid>
</Grid>
And the code behind:
private void theExpander_Collapsed(object sender, RoutedEventArgs e)
{
theColumn.Width = GridLength.Auto;
}
It's not the way I would prefer to do this, but trying to use a style trigger on the column definition just does not work.
I took Terrence's solution (comment in Ghostriders answer) and fixed a little problem that the default values were sometimes not correctly applied.
The source can be found here: https://gist.github.com/medarion/5ff6d04be5630748e8bf92006d0b4472
Usage is unchanged:
<Grid.ColumnDefinitions>
<controls:CollapsibleColumnDefinition
CollapsedWidth="0" ExpandedWidth="500" IsExpanded="{Binding HeaderVisible}"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
I am Having requirement on WPF Datagrid row,Whenever user selects a DatagridRow,corresponding datagrid Cells borders should have thickness of 1 or 2 .
or Provide margin for textboxes/Textblocks within in DatagridCell.
With regards,
Mahens
I'm not sure if this is exactly what you're looking for, but here's an example of modifying the default listboxitem style for a gridview (NOTE the top level Grid is the top-level element in a xaml file):
<Grid>
<Grid.Resources>
<Style x:Key="itemstyle" TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="BorderThickness" Value="3"/>
<Setter Property="BorderBrush" Value="Black"/>
</Trigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<ListView Name="grid" ItemContainerStyle="{StaticResource itemstyle}">
<ListView.View>
<GridView>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Path=Name}"/>
<GridViewColumn Header="Age" DisplayMemberBinding="{Binding Path=Age}"/>
</GridView>
</ListView.View>
</ListView>
</Grid>
I just created a generic Person type with a Name string property and an int Age property. I added a few of these to a list and set the ItemsSource of grid to the List.