ListView Change background of single item - c#

Let's assume I have the following listview:
<ListView Name="list" />
and the following code inside my function:
list.Items.Add("red");
list.Items.Add("green");
How can I change the background of the first item to red and second one to green?

You can make use of ItemContainerStyle to define a style for the items.
In the style you can bind the Background property to the item itself which is representation of the color.
Now the implicit color converter will convert to appropriate color and set to the background property.
example
<ListView Name="list" >
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Background"
Value="{Binding}" />
</Style>
</ListView.ItemContainerStyle>
</ListView>
result
Alternate approch
here is how you can use Triggers to set the values conditionally
I used DataTrigger to see if the item meet my condition and then I can set the desired color via a setter
<ListView Name="list">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Style.Triggers>
<DataTrigger Binding="{Binding}"
Value="red">
<Setter Property="Background"
Value="red" />
</DataTrigger>
<DataTrigger Binding="{Binding}"
Value="mygreen">
<Setter Property="Background"
Value="green" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
</ListView>
result
in above example you can see that the background color is only applied to only desired items eg. red & mygreen

Related

CellStyle based on RowStyle in WPF

I have a WPF DataGrid represented in XAML. I'm using a RowStyle for my grid's TableView but also need to set some properties for specific cells. I need those cells to have the properties of the row style and apply the extra properties from the cell style on top of those.
What I would need is something like this, although this doesn't work as it's saying:
Target type 'CellContentPresenter' is not convertible to base type 'GridRowContent'
<Style x:Key="MyGridRowStyle"
BasedOn="{StaticResource {themes:GridRowThemeKey ResourceKey=RowStyle}}"
TargetType="{x:Type dxg:GridRowContent}">
<Setter Property="Height"
Value="25" />
<Style.Triggers>
...
</Style.Triggers>
</Style>
<Style x:Key="MyCellStyle"
BasedOn="{StaticResource MyGridRowStyle}"
TargetType="{x:Type dxg:CellContentPresenter}">
<Style.Triggers>
...
</Style.Triggers>
</Style>
I've also tried not specifying the BasedOn property for MyCellStyle but that doesn't work either.
I use the MyCellStyle like this:
<dxg:GridColumn Header="My Header"
FieldName="MyFieldName"
Width="100"
CellStyle="{StaticResource MyCellStyle}" />
and MyGridRowStyle like this on the TableView:
RowStyle="{StaticResource MyGridRowStyle}"
How can I make the cell style only change the properties specified in MyCellStyle and use the values specified in MyGridRowStyle for the other properties?
You can't base a CellContentPresenter style on a GridRowContent style. These are two completely different types and just because they may happen to have some properties that have the same name these are still completely different and independant properties with no relationship to each other.
The best thing you can do is to define the common values as separate resources and use these resources in both styles, e.g.:
<Window.Resources>
<s:Double x:Key="commonHeight">25</s:Double>
<SolidColorBrush x:Key="commonBg">Red</SolidColorBrush>
<Style x:Key="MyCellStyle" TargetType="{x:Type dxg:CellContentPresenter}">
<Setter Property="Height" Value="{StaticResource commonHeight}" />
<Setter Property="Background" Value="{StaticResource commonBg}" />
</Style>
<Style x:Key="MyGridRowStyle" BasedOn="{StaticResource {themes:GridRowThemeKey ResourceKey=RowStyle}}" TargetType="{x:Type dxg:GridRowContent}">
<Setter Property="Height" Value="{StaticResource commonHeight}" />
<Setter Property="Background" Value="{StaticResource commonBg}" />
</Style>
</Window.Resources>
But you still need to define all setters in both styles.
based on normal WPF DataGrid you could try this and expand it for dxg
the class DataGridCell is derived from ContentControl (that is a child from Content).
the class DataGridRow is derived from Control.
now you could try the following:
<Style x:Key="BaseStyle" TargetType="Control" >
<!-- Maybe add BaseStyle / theme here with BasedOn -->
<Setter Property="Height" Value="25" />
<!-- Row and Column defaults -->
</Style>
<Style x:Key="MyGridRowStyle" BasedOn="{StaticResource BaseStyle}"
TargetType="DataGridRow">
<!-- Row specific implementation -->
</Style>
<Style x:Key="MyCellStyle" BasedOn="{StaticResource BaseStyle}"
TargetType="DataGridCell">
<!-- Column specific implementation -->
</Style>
summary:
use base type of both Row and Column classes for your BaseStyle and use this one as BasedOn. For dxg you can extend it by your own...
My understanding of the question: values of the cell style should change based off of values in the style of the row it is in.
Trigger off of value
Here is a simple working example (test it by changing the DataGridRow Background to Red, you will notice that the cell's foreground changes to Blue):
<DataGrid>
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Setter Property="Background" Value="White"/>
</Style>
</DataGrid.RowStyle>
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=DataGridRow, Mode=FindAncestor}, Path=Background}" Value="Red">
<Setter Property="Foreground" Value="Blue"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.CellStyle>
</DataGrid>
You can do a similar binding to directly set properties of the CellStyle to the value of properties of the row it is in.
Relative bind directly to a property
<DataGrid x:Name="dataGrid1" ItemsSource="{Binding Collection}">
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Setter Property="Height" Value="20"/>
</Style>
</DataGrid.RowStyle>
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="FontSize" Value="{Binding RelativeSource={RelativeSource AncestorType=DataGridRow, Mode=FindAncestor}, Path=Height}"/>
</Style>
</DataGrid.CellStyle>
</DataGrid>
Explanation
RelativeBinding works due to the fact that DataGridCells are eventual children of DataGridRows as can been seen in this screenshot of the visual tree of a DataGrid:

How to change background of DataGridCell when IsEditing=True in WPF

Setting background works fine for DataGridCheckBoxColumn but not for DataGridTextColumn. I set it for cell in resources:
<Style TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="#ffff00" />
</Trigger>
<Trigger Property="IsEditing" Value="True">
<Setter Property="BorderThickness" Value="1" />
<Setter Property="BorderBrush" Value="#00ff00" />
<Setter Property="Background" Value="#00ff00" />
</Trigger>
</Style.Triggers>
</Style>
Is there any solution for this issue?
You should add magic string:
<SolidColorBrush x:Key="{x:Static SystemColors.WindowBrushKey}" Color="Transparent" />
in your resources, for example in <Window.Resources>.
In this case, when IsEditing="True" color is assigned by default (White), which is taken from the SystemColors. But then you need to explicitly set the color for the main panel or for Window.
Or set this string in <DataGrid.Resources> with Background="White":
<DataGrid Background="White" ...>
<DataGrid.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.WindowBrushKey}" Color="Transparent" />
</DataGrid.Resources>
...
</DataGrid>
The accepted answer is great until it causes side-effects. In my case, it was causing the editing caret to be invisible when editing, probably because setting the "magic" system color was messing with the logic that sets the caret color automatically.
A better solution is to simply override the style that the grid uses when it's in edit mode (the DataGridTextColumn.EditingElementStyle), like this:
<DataGrid>
<DataGrid.Columns>
<DataGridTextColumn>
<DataGridTextColumn.EditingElementStyle>
<Style TargetType="TextBox">
<Setter Property="Background" Value="#00ff00"/>
</Style>
</DataGridTextColumn.EditingElementStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
Yet another solution is to make your own DataGridTemplateColumn, as shown here. This gives you full control over your column, instead of fighting against whatever the built-in DataGridTextColumn wants to do. This, however, may be too much power, as it may force you to deal with details you may not want to. But FWIW, it's what worked in my case.

Changing the color of text in a ListView

I have a ListView with 3 items in my xaml:
<ListView Height="768" Width="220" Background="Silver" >
<x:String>Item 1</x:String>
<x:String>Item 2</x:String>
<x:String>Item 3</x:String>
</ListView>
How can I change the color/text size of the text in the row?
Also as a bonus question, how can I get it so that the background of the row and the text color changes then an item is selected?
The solution to this is quite simple:
If you want to set the same color for all items then the following way will be appropriate:
<ListView Height="768" Width="220" Background="Silver">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Foreground" Value="Blue"></Setter>
</Style>
</ListView.ItemContainerStyle>
<system:String>Item 1</system:String>
<system:String>Item 2</system:String>
<system:String>Item 3</system:String>
</ListView>
In order for particular item to have a unique color you should place the AlternationCount property for the ListView itself:
<ListView AlternationCount="50" Height="768" Width="220" Background="Silver">
and a trigger within ItemContainerStyle. The Trigger Value properties here are the indexes of the items:
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Style.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter Property="Foreground" Value="Red"></Setter>
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Foreground" Value="Blue"></Setter>
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="2">
<Setter Property="Foreground" Value="Black"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
At this point it's easy to figure out how to manipulate properties other than Foreground.

WPF How to make the background of DataGridComboBoxColumn to be the same as DataGridTextBoxColumn

I have a datagridCombox Column in datagrid.
In order for the combobox to show like a combobox all the time (click or not)
The combobox is implemented as this
xmlns:dg="http://schemas.microsoft.com/wpf/2008/toolkit"
<dg:DataGridTemplateColumn Header="Time Unit" x:Name="timeUnit" >
<dg:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox SelectedValue="{Binding RelParams.TimeUnit}"
Background="White" BorderBrush="{x:Null}"
ItemsSource ="{Binding TimeUnitList}" >
</ComboBox>
</DataTemplate>
</dg:DataGridTemplateColumn.CellTemplate>
</dg:DataGridTemplateColumn>
Now the issue is the datagridrow has alternation background.
I want the combobox in the datagridrow to use the same background as the textbox column in the datagridrow. Also when the datagridrow is selected, the combobox should be highlighted in the same color as the rest of the row. How to accomplish this? Thanks
<Style x:Key="DataGridCellStyle" TargetType="{x:Type dg:DataGridCell}">
<Setter Property="ContextMenu" Value="{DynamicResource cellContextMenu}" />
</Style>
<Style x:Key="DataGridRowStyle" TargetType="{x:Type dg:DataGridRow}">
<Style.Triggers>
<Trigger Property="AlternationIndex" Value="1" >
<Setter Property="Background" Value="Beige" />
</Trigger>
</Style.Triggers>
<Setter Property="Margin" Value="0 2 0 2" />
</Style>
<Style x:Key="DataGridStyle" TargetType="{x:Type dg:DataGrid}">
<Setter Property="AlternationCount" Value="2" />
<Setter Property="RowStyle" Value="{StaticResource DataGridRowStyle}" />
<Setter Property="CellStyle" Value="{StaticResource DataGridCellStyle}" />
</Style>
You can try setting the Background Property of the Combobox in your DataTemplate to Transparent.

Trouble styling data-bound WPF ComboBoxItem

I have a ComboBox, bound to a DataTable. I'm trying to add an extra ComboBoxItem to the top of the list, where I can put a link to customize the list. Currently I am just inserting a dummy row to the top of my DataTable, and then using a DataTrigger on the ComboBox to make it appear correctly. However, I'm not quite getting the correct result.
I've tried two methods. In the first, my DataTrigger replaces the dummy item with a ControlTemplate, which contains a TextBlock.
<ComboBox IsEditable="True" Name="comboWell" ItemsSource="{Binding}" DisplayMemberPath="wellId">
<ComboBox.ItemContainerStyle>
<Style TargetType="{x:Type ComboBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding wellId}" Value="(settings)">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBoxItem">
<TextBlock Text="Customize..." />
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
The result looks right, but there is no mouseover highlight on that item. The rest of the list works fine, but that one item doesn't react at all when I mouse over it. I've tried adding extra triggers and styles to apply a mouseover effect, but I get no change.
The second method I tried was just to alter the appearance of the item rather than completely replace it with a ControlTemplate.
<ComboBox IsEditable="True" Name="comboWell" ItemsSource="{Binding}" DisplayMemberPath="wellId">
<ComboBox.ItemContainerStyle>
<Style TargetType="{x:Type ComboBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding wellId}" Value="(settings)">
<Setter Property="Content" Value="Customize..." />
</DataTrigger>
</Style.Triggers>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
This one functions like a regular list item, mouseover works fine. However, the item is blank. Neither the original text, nor the text I try to set in the DataTrigger, are there. No errors, just an empty list item.
Is there a better way to accomplish this?
Remove the DisplayMemberPath and add the default Content to the Style
<ComboBox IsEditable="True" Name="comboWell" ItemsSource="{Binding }">
<ComboBox.ItemContainerStyle>
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="Content" Value="{Binding wellId}" />
<Style.Triggers>
<DataTrigger Binding="{Binding wellId}" Value="(settings)">
<Setter Property="Content" Value="Customize..." />
</DataTrigger>
</Style.Triggers>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
DisplayMemberPath is actually a shortcut way of saying the item template should just be a TextBlock with it's Text bound to the DisplayMemberPath item, and I am guessing it was overwritting whatever you had in the Style.

Categories