最近用到wpf开发程序,使用了几种动态设置控件外观的方法,跟大家分享一下。
List控件DataTemplate指的是如何表现数据呈现形式的模板(这并不包括包裹DataTemplate的控件部分),一个list控件条目可以根据自己的数据使用不同的模板,可以使用ItemTemplateSelector属性。若需要对整个条目做自定义设置,就要用到ItemContainerStyle,同样一个list控件条目可以根据自己的数据使用不同的Item样式。我写了一个小Demo,展示了这几种用法。
<Window x:Class="Test.TemplateSelectorWnd"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:selector="clr-namespace:Test.Selector"
Title="TemplateSelectorWnd" Height="300" Width="300">
<Window.Resources>
<DataTemplate x:Key="kidDataTemplate">
<TextBlock Text="{Binding Name}" Foreground="#FFFF0000"/>
</DataTemplate>
<DataTemplate x:Key="youngDataTemplate">
<TextBlock Text="{Binding Name}" Foreground="#FF00FF00"/>
</DataTemplate>
<DataTemplate x:Key="adultDataTemplate">
<TextBlock Text="{Binding Name}" Foreground="#FF0000FF"/>
</DataTemplate>
<selector:PersonDataSelector x:Key="myDataTemplateSelector" KidDataTemplate="{StaticResource kidDataTemplate}"
YoungDataTemplate="{StaticResource youngDataTemplate}"
AdultDataTemplate="{StaticResource adultDataTemplate}"/>
<Style x:Key="InsertItemContainerStyle" TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding Age}" Value="10">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<TextBox Text="{Binding Name}" Foreground="#FFFF0000"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Age}" Value="20">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<TextBlock Text="{Binding Name}" Foreground="#FF00FF00"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Age}" Value="30">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<TextBlock Text="{Binding Name}" Foreground="#FF0000FF"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
<Style x:Key="kidTemplateStyle" TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<TextBox Text="{Binding Name}" Foreground="#FFFF0000"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="youngTemplateStyle" TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<TextBox Text="{Binding Name}" Foreground="#FF00FF00"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="adultTemplateStyle" TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<TextBox Text="{Binding Name}" Foreground="#FF0000FF"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<selector:PersonContainerSelector x:Key="personContainerSelector" KidTemplate="{StaticResource kidTemplateStyle}" YoungTemplate="{StaticResource youngTemplateStyle}"
AdultTemplate="{StaticResource adultTemplateStyle}"/>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="20"/>
<RowDefinition Height="*"/>
<RowDefinition Height="20"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<DockPanel LastChildFill="True">
<Button Content="Change Age" Command="{Binding ChangeAgeCommand}" DockPanel.Dock="Bottom"/>
<ListBox ItemTemplateSelector="{StaticResource myDataTemplateSelector}" ItemsSource="{Binding Persons}">
</ListBox>
</DockPanel>
<DockPanel Grid.Row="2" LastChildFill="True">
<Button Content="Change Age" Command="{Binding ChangeAgeCommand}" DockPanel.Dock="Bottom"/>
<ListBox ItemsSource="{Binding Persons}" ItemContainerStyle="{StaticResource InsertItemContainerStyle}">
</ListBox>
</DockPanel>
<DockPanel Grid.Row="4" LastChildFill="True">
<Button Content="Change Age" Command="{Binding ChangeAgeCommand}" DockPanel.Dock="Bottom"/>
<ListBox Name="_lbView" ItemsSource="{Binding Persons}" ItemContainerStyleSelector="{StaticResource personContainerSelector}">
</ListBox>
</DockPanel>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CncertOfflineMgr.ViewModel;
namespace Test
{
public class Person : NotificationObject
{
private string _name;
private int _age;
public string Name
{
get
{
return _name;
}
set
{
_name = value;
RaisePropertyChanged("Name");
}
}
public int Age
{
get
{
return _age;
}
set
{
_age = value;
RaisePropertyChanged("Age");
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
namespace Test.Selector
{
public class PersonDataSelector : DataTemplateSelector
{
public DataTemplate KidDataTemplate { get; set; }
public DataTemplate YoungDataTemplate { get; set; }
public DataTemplate AdultDataTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
Person person = (Person)item;
if (person.Age >= 30)
{
return AdultDataTemplate;
}
else if (person.Age >= 20)
{
return YoungDataTemplate;
}
return KidDataTemplate;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
namespace Test.Selector
{
public class PersonContainerSelector : StyleSelector
{
public Style KidTemplate { get; set; }
public Style YoungTemplate { get; set; }
public Style AdultTemplate { get; set; }
public override Style SelectStyle(object item, DependencyObject container)
{
Person person = (Person)item;
if (person.Age >= 30)
{
return AdultTemplate;
}
else if (person.Age >= 20)
{
return YoungTemplate;
}
return KidTemplate;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CncertOfflineMgr.ViewModel;
using System.Collections.ObjectModel;
using System.Windows.Input;
namespace Test.ViewModel
{
class TemplateSelectorWndViewModel : NotificationObject
{
private ObservableCollection<Person> _persons = new ObservableCollection<Person>();
private ICommand _changeAgeCommand;
public ObservableCollection<Person> Persons
{
get
{
return _persons;
}
}
public TemplateSelectorWndViewModel()
{
_persons.Add(new Person() { Name = "bixy", Age = 30 });
_persons.Add(new Person() { Name = "wh", Age = 20 });
_persons.Add(new Person() { Name = "lgy", Age = 10 });
}
private void ExecuteChangeAgeCommand(object parameter)
{
//_persons[0] = new Person() { Name = "bixy", Age = 10 };
_persons[0].Age = 10;
}
public ICommand ChangeAgeCommand
{
get
{
if (_changeAgeCommand == null)
{
_changeAgeCommand = new RelayCommand<object>(ExecuteChangeAgeCommand);
}
return _changeAgeCommand;
}
}
}
}
其中第一中方法展示了使用ItemTemplateSelector控制外观的方法,第二种展示了使用ItemContainerStyle控制外观的方法,第三种展示了使用ItemContainerStyleSelector控制外观的方法。
单击按钮,执行ExecuteChangeAgeCommand方法后,发现第一种和第三种控制外观的方法并不会随着子数据的变化而变化,而第二种会变化。若使用语句
_persons[0] = new Person() { Name = "bixy", Age = 10 };
则第一种、第二种及第三种会发生变化。说明selector绑定的是其item数据,而第二种采用的数据trigger方式会根据子数据的变化而触发其动作。