I am new to WPF and I have read a lot of similar questions on the web, but I still do not get my listview work. I want to change the background color of a list view element depending of a property (red, yellow or green)
The itemsSource
of my ListView is an observable list of this class:
public class ConnectionItem
{
public ConnectionItem(string name)
{
Name = name;
}
public string Name { get; }
private string _color = "Red";
public string Color { get => _color; }
private ConnectionStatus _status;
public ConnectionStatus Status
{
set
{
if (value == _status)
{
return;
}
else
{
switch (value)
{
case ConnectionStatus.Connected:
_color = "Yellow";
break;
case ConnectionStatus.Ready:
_color = "Green";
break;
default:
_color = "Red";
break;
}
}
}
}
}
And I have defined my listview in xaml as follows:
<ListView x:Name="lvConnections">
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<EventSetter Event="MouseDoubleClick" Handler="ListViewItem_MouseDoubleClick" />
</Style>
</ListView.ItemContainerStyle>
<ListView.Resources>
<Style TargetType="ListViewItem">
<Style.Triggers>
<DataTrigger Binding="{Binding Color}" Value="Green">
<Setter Property="Background" Value="Green"/>
</DataTrigger>
<DataTrigger Binding="{Binding Color}" Value="Red">
<Setter Property="Background" Value="Red"/>
</DataTrigger>
<DataTrigger Binding="{Binding Color}" Value="Yellow">
<Setter Property="Background" Value="Yellow"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.Resources>
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel Width="150" MaxHeight="50" Grid.Column="0" Grid.Row="0" Orientation="Horizontal" >
<TextBlock VerticalAlignment="Center" Text="{Binding Name}" FontWeight="ExtraBlack" TextWrapping="Wrap" Padding="10"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The binding does not work and all my listview element have no background color. I do not need exactly the same solution via ListView.Resources
binding, but I also have did not succed in other approaches.
bind the background to the Color property.
<ListView x:Name="lvConnections">
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<EventSetter Event="MouseDoubleClick" Handler="ListViewItem_MouseDoubleClick" />
</Style>
</ListView.ItemContainerStyle>
<ListView.Resources>
<Style TargetType="ListViewItem">
<Setter Property="Background" Value="{Binding Color}"/>
</Style>
</ListView.Resources>
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel Width="150" MaxHeight="50" Grid.Column="0" Grid.Row="0" Orientation="Horizontal" >
<TextBlock VerticalAlignment="Center" Text="{Binding Name}" FontWeight="ExtraBlack" TextWrapping="Wrap" Padding="10"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
and set the Color property to a brush object
public class ConnectionItem
{
public ConnectionItem(string name)
{
Name = name;
}
public string Name { get; }
private Brush _color = Brushes.Red;
public Brush Color { get => _color; }
private ConnectionStatus _status;
public ConnectionStatus Status
{
set
{
if (value == _status)
{
return;
}
else
{
switch (value)
{
case ConnectionStatus.Connected:
_color = Brushes.Yellow;
break;
case ConnectionStatus.Ready:
_color = Brushes.Green;
break;
default:
_color = Brushes.Red;
break;
}
}
}
}
}
If you move the trigger Style
from ListView.Resources
to StackPanel.Resources
(and change the TargetType
to StackPanel
) then the background colors will display using this approach.
<StackPanel Width="150" MaxHeight="50" Grid.Column="0" Grid.Row="0" Orientation="Horizontal">
<StackPanel.Resources>
<Style TargetType="StackPanel">
<Style.Triggers>
<DataTrigger Binding="{Binding Color}" Value="Green">
<Setter Property="Background" Value="Green"/>
</DataTrigger>
<DataTrigger Binding="{Binding Color}" Value="Red">
<Setter Property="Background" Value="Red"/>
</DataTrigger>
<DataTrigger Binding="{Binding Color}" Value="Yellow">
<Setter Property="Background" Value="Yellow"/>
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Resources>
<TextBlock VerticalAlignment="Center" Text="{Binding Name}" FontWeight="ExtraBlack" TextWrapping="Wrap" Padding="10"/>
</StackPanel>
You will also need to look at implementing INotifyPropertyChanged
on ConnectionItem
for the colors to update when Status
is changed.
public class ConnectionItem : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public ConnectionItem(string name)
{
Name = name;
}
public string Name { get; }
private string _color = "Red";
public string Color
{
get => _color;
set
{
if (value == _color) return;
_color = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Color"));
}
}
private ConnectionStatus _status;
public ConnectionStatus Status
{
get => _status;
set
{
if (value == _status) return;
_status = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Status"));
switch (value)
{
case ConnectionStatus.Connected:
Color = "Yellow";
break;
case ConnectionStatus.Ready:
Color = "Green";
break;
default:
Color = "Red";
break;
}
}
}
}
Note that Status
and Color
now have both get
and set
accessors and that that Status
is setting the Color
property rather than directly setting the _color
field.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
lvConnections.ItemsSource = new ObservableCollection<ConnectionItem>()
{
new ConnectionItem("Starts Connected") { Status = ConnectionStatus.Connected, },
new ConnectionItem("Starts Ready") { Status = ConnectionStatus.Ready, },
new ConnectionItem("Starts Default"),
};
}
private void ListViewItem_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
var item = (sender as ListViewItem)?.DataContext as ConnectionItem;
switch (item.Status)
{
case ConnectionStatus.Connected:
item.Status = ConnectionStatus.Ready;
break;
case ConnectionStatus.Ready:
item.Status = ConnectionStatus.Disconnected;
break;
default:
item.Status = ConnectionStatus.Connected;
break;
}
}
}
You can even go one step further, remove the Color
property from ConnectionItem
altogether (and the switch setting it in Status
) and use Status
values in the Style
triggers.
ConnectionItem
public class ConnectionItem : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public ConnectionItem(string name)
{
Name = name;
}
public string Name { get; }
private ConnectionStatus _status;
public ConnectionStatus Status
{
get => _status;
set
{
if (value == _status) return;
_status = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Status"));
}
}
}
Style
<Style TargetType="StackPanel">
<Style.Triggers>
<DataTrigger Binding="{Binding Status}" Value="Ready">
<Setter Property="Background" Value="Green"/>
</DataTrigger>
<DataTrigger Binding="{Binding Status}" Value="Disconnected">
<Setter Property="Background" Value="Red"/>
</DataTrigger>
<DataTrigger Binding="{Binding Status}" Value="Connected">
<Setter Property="Background" Value="Yellow"/>
</DataTrigger>
</Style.Triggers>
</Style>
Your ListViewItem
style doesn't get applied because your have set the ItemContainerStyle
property to another Style
. You should move your triggers to the ItemContainerStyle
:
<ListView x:Name="lvConnections">
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<EventSetter Event="MouseDoubleClick" Handler="ListViewItem_MouseDoubleClick" />
<Style.Triggers>
<DataTrigger Binding="{Binding Color}" Value="Green">
<Setter Property="Background" Value="Green"/>
</DataTrigger>
<DataTrigger Binding="{Binding Color}" Value="Red">
<Setter Property="Background" Value="Red"/>
</DataTrigger>
<DataTrigger Binding="{Binding Color}" Value="Yellow">
<Setter Property="Background" Value="Yellow"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel Width="150" MaxHeight="50" Grid.Column="0" Grid.Row="0" Orientation="Horizontal" >
<TextBlock VerticalAlignment="Center" Text="{Binding Name}" FontWeight="ExtraBlack" TextWrapping="Wrap" Padding="10"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.