First item custom style border in ListView - wpf

How can I set different style for first item in ListView? In my case, I want to change first item border, to get GUI like this:
My current code (no top border):
<ListView
ItemsSource="{Binding MyData}">
<ListView.ItemContainerStyle>
<Setter Property="BorderThickness" Value="0,0,0,1" />
</ListView.ItemContainerStyle>
</ListView>

There is a very simple solution. You don't have to write custom converters etc. Use PreviousData in RelativeSource
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="BorderThickness" Value="0,0,0,1" />
<Style.Triggers>
<DataTrigger
Binding="{Binding RelativeSource={RelativeSource PreviousData}}" Value="{x:Null}">
<Setter Property="BorderThickness" Value="0,1,0,1"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>

Related

Set a trigger's property to a child

How can I set the trigger to be depend on a children's property?
Like I want to change the header of my Expander depending whether the Expander's ListView
does have children or not.
But I always get an Comilor error, that HasItems can not be resolved...
<Expander Header="Expand to add new ports">
<Expander.Resources>
<Style TargetType="{x:Type Expander}">
<Style.Triggers>
<Trigger Property="Content.HasItems" Value="False">
<Setter Property="Header" Value="No children" />
</Trigger>
</Style.Triggers>
</Style>
</Expander.Resources>
<ListView ItemsSource="{Binding Path=SomeItems}">
</ListView>
You can use a DataTrigger bound to the ListView using ElementName:
<Expander>
<Expander.Resources>
<Style TargetType="{x:Type Expander}">
<Setter Property="Header" Value="Expand to add new ports" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=ListView, Path=HasItems}" Value="False">
<Setter Property="Header" Value="No children" />
</DataTrigger>
</Style.Triggers>
</Style>
</Expander.Resources>
<ListView x:Name="ListView" ItemsSource="{Binding Path=SomeItems}">
</ListView>
</Expander>
Also note that if you set a property along with the declaration of the control the Setter in the trigger won't have any effect.
Use this:
<Setter Property="Header" Value="Expand to add new ports" />
Instead of this:
<Expander Header="Expand to add new ports">
There are multiple issues in your code -
First, you should set the property in style setter instead of declaring it locally.
Second, use DataTrigger in place of Trigger.
<Expander>
<Expander.Style>
<Style TargetType="{x:Type Expander}">
<Setter Property="Header" Value="Expand to add new ports"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=SomeItems.Count}" Value="0">
<Setter Property="Header" Value="No children" />
</DataTrigger>
</Style.Triggers>
</Style>
</Expander.Style>
<ListView ItemsSource="{Binding Path=SomeItems}">
</ListView>
</Expander>

DataGridCell Validation.ErrorTemplate ignored

I'm trying to set the Validation.ErrorTemplate of the DataGridCells, here's the xaml code:
<Style x:Key="{x:Type DataGridCell}" x:Uid="dataGridCellErrorTemplate" TargetType="{x:Type DataGridCell}">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate >
<Border BorderBrush="Green" BorderThickness="2" ToolTip="Heidenei"></Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<!-- following line only for demonstration that the setter is working ... -->
<Setter Property="Background" Value="Aquamarine"></Setter>
</Style>
while the background of the datagridcells is successfully colored green (independant from any validation result) the used Validation.ErrorTemplate is still the default one, i.e. the red border.
I know there have been similar issues here in stackoverflow, e.g.
Styling DataGridCell Error Template
but they do not really solve my problem.
Any help is appreciated
Frank
I believe that I'm experiencing the same issue.
When using a DataGridTemplateColumn the content is presented with a ContentPresenter. This content presenter uses the default error template.
I can't find a direct way to remove this template for an individual DataGridTemplateColumn but you can remove it for all content presenters in the DataGrid by adding a style to the DataGrid's resources.
<DataGrid.Resources>
<Style TargetType="ContentPresenter">
<Setter Property="Validation.ErrorTemplate" Value="{x:Null}"/>
</Style>
</DataGrid.Resources>
I had luck removing the irritating red border by using the following TextBlock style.
<Style TargetType="TextBlock">
<Setter Property="Validation.ErrorTemplate" Value="{x:Null}"/>
</Style>
From Microsoft, attempting to change the ErrorTemplate on a DataGrid just will not work. Their example is a trigger in a style where you set the background as red (or whatever) when the Validation.HasError property is true.
To customize cell validation feedback: Set the column's EditingElementStyle property to a style appropriate for the column's editing control. Because the editing controls are created at run time, you cannot use the Validation.ErrorTemplate attached property like you would with simple controls.
This approach worked for me, and it also removed the default error template (the red border around the cell). The red border is replaced with the BorderBrush in the style, and the little exclamation point can be removed by setting the RowValidationErrorTemplate property of DataGrid to {x:Null}. I have looked at the other related questions on SO and have not found this solution anywhere. Here is an example of my solution, with the style definition and a DataGridTextColumn which uses the style:
<Style
x:Key="DataGridTextBoxValidationStyle"
TargetType="{x:Type TextBox}">
<Setter Property="Padding" Value="-2" />
<Setter Property="MaxWidth" Value="250"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Width" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridCell}}, Path=ActualWidth}"/>
<Setter Property="Height" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridCell}}, Path=ActualHeight}"/>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="Background" Value="Firebrick" />
<Setter Property="Foreground" Value="White" />
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" />
<Setter Property="BorderBrush" Value="Firebrick"/>
</Trigger>
</Style.Triggers>
</Style>
<DataGrid RowValidationErrorTemplate="{x:Null}">
<DataGrid.Columns>
<DataGridTextColumn
EditingElementStyle="{StaticResource DataGridTextBoxValidationStyle}">
<!-- other stuff here -->
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>

Using Picture or Icon instead of DataGridCheckBoxColumn in WPF

I want to change the CheckBox which is inside of a DataGridColumn into an image when it is checked and another when it is unchecked, How can i do ?
Ps: My DataGridCheckBoxColumn is defined like this:
<DataGridCheckBoxColumn Header="Priority" Binding="{Binding PRIORITY, Converter={StaticResource converter}}"/>
Converter is converting bytes to boolean.
Use the ElementStyle and EditingElementStyle properties to create and set a different Template for the CheckBox which fits that.
e.g.
<DataGridCheckBoxColumn Binding="{Binding IsActive}">
<DataGridCheckBoxColumn.ElementStyle>
<Style TargetType="{x:Type CheckBox}">
<Setter Property="IsEnabled" Value="False" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<Image MaxWidth="32" MaxHeight="32">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Setter Property="Source" Value="Images/Error.ico" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, RelativeSource={RelativeSource AncestorType=CheckBox}}" Value="True">
<Setter Property="Source" Value="Images/Default.ico" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGridCheckBoxColumn.ElementStyle>
</DataGridCheckBoxColumn>
This makes the column display an image based on IsChecked, the URIs are just hardcoded and the CheckBox is disabled because editing in the ElementStyle does not change any properties on the bound object. Its only purpose is to display the approriate image.
(The EditingElementStyle is not set here so if the user clicks the cell again to edit it a normal CheckBox appears which can be checked or unchecked.)

Trigger for a ContextMenu Visibility?

I have a Listbox that starts off with no items inside. When a user uses the GUI to select a value from a combobox and clicks the add Button, the the listbox gets an item added. The Listbox also has a contextmenu set.
How can i use XAML to make sure that the Listbox.contextmenu.Visibility property set to hidden when there are no items in the listbox??
UPDATE
I actually used this code in the end. Please comment on its appropriatness
<Style TargetType="ListBox">
<Style.Resources>
<ContextMenu x:Key="cm">
<MenuItem Header="Buy"/>
<MenuItem Header="Sell"/>
</ContextMenu>
</Style.Resources>
<Setter Property="ContextMenu" Value="{StaticResource cm}"/>
<Style.Triggers>
<Trigger Property="ListBox.HasItems" Value="False">
<Setter Property="ContextMenu.Visibility" Value="Hidden"/>
</Trigger>
</Style.Triggers>
</Style>
I do not think that messing with the visibility of the ContextMenu is a good idea, just null out the whole menu if the list is empty.
e.g.
<Style TargetType="{x:Type ListBox}">
<Style.Resources>
<ContextMenu x:Key="cm">
<!-- Menu here -->
</ContextMenu>
</Style.Resources>
<Setter Property="ContextMenu" Value="{StaticResource cm}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Items.Count, RelativeSource={RelativeSource Self}}" Value="0">
<Setter Property="ContextMenu" Value="{x:Null}" />
</DataTrigger>
</Style.Triggers>
</Style>
You could also choose to only define ContextMenus on the items themselves using the ItemContainerStyle, then no ContextMenu can be opened without items but that might of course not fit your scenario.

WPF Grid - How to apply a style for just one column?

I have a WPF Grid with many rows and columns, all containing things like TextBlocks and TextBoxes.
For this specific situation I want all the stuff in column 1 to have padding, and all the stuff in column 2 to be aligned right. It seems to be very non-WPF to have to set those properties on each item in the grid.
I know I can create a style for all TextBlocks within a grid by doing something like this:
<Grid>
<Grid.Resources>
<Style TargetType="{x:Type TextBox}">
<Setter Property="HorizontalAlignment" Value="Right"/>
</Style>
</Grid.Resources>
</Grid>
But is there a way to apply that style to only the controls in say, column 2?
Should I be using a different control?
Here's what I usually do:
<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource {x:Type TextBlock}}">
<Style.Triggers>
<Trigger Property="Grid.Column" Value="0">
<Setter Property="Margin" Value="0,0,2,0" />
</Trigger>
<Trigger Property="Grid.Column" Value="2">
<Setter Property="Margin" Value="20,0,2,0" />
</Trigger>
</Style.Triggers>
</Style>
You can define some styles like below and assign them to your Column.ElementStyle property:
<Window.Resources>
<Style x:Key="elementStyle" TargetType="TextBlock">
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Margin" Value="2,0,2,0" />
</Style>
<Style x:Key="rightElementStyle" BasedOn="{StaticResource elementStyle}" TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Right" />
</Style>
<Style x:Key="centerElementStyle" BasedOn="{StaticResource elementStyle}" TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
</Style>
</Window.Resources>
<dg:DataGrid AutoGenerateColumns="False">
<dg:DataGrid.Columns>
<dg:DataGridTextColumn Binding={Binding Path=Name}
Header="Name"
ElementStyle="{StaticResource centerElementStyle}"/>
<dg:DataGridTextColumn Binding={Binding Path=Amount}
Header="Amount"
ElementStyle="{StaticResource rightElementStyle}"/>
</dg:DataGrid.Columns>
</dg:DataGrid>

Resources