假設我有一個 ListBox 且裡面放了 6 個項目,我想要在特殊情況時讓某個項目被 Highlight 起來,這個項目要和其他一般的項目有著不同的視覺效果,舉個例子來比較一下特殊項目及一般項目的外觀:
一般項目:
黑色字體
字體 12 px
背景白色
特殊項目:
淺藍色字體
字體 15 px
背景灰色
在一般的情況下我可能會定義這樣子的資料結構來使用
public class DataItem
{
// 為了顯示而建立的屬性
public Color BackgroundColor { get; set; }
public Int32 FontSize { get; set; }
public SolidColorBrush FontBrush { get; set; }
// 以下才是真正屬於 DataItem 的屬性
public Boolean Special { get; set; }
public String Header { get; set; }
public String Text { get; set; }
}
這種情況下我的列表愈大,DataItem 中額外的 Property 所造成的影響也就愈大,所以我將最上面三個 Property 移除,改成利用 Special 這個 Property 配合 Converter 來達到一樣的效果,還給 DataItem 這個資料結構該有的樣子。
首先定義三個 Converter,分別根據 Special 這個布林值給出對應的外觀型態
// 將布林值轉成顏色
public class BooleanToHighlightBackgroundConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (value is Boolean && (Boolean)value) ? Colors.Gray : Colors.White;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
Colors color = value as Colors;
return Colors.Gray.Equals(color);
}
}
// 將布林值轉成字體尺寸
public class BooleanToHighlightFontSizeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (value is Boolean && (Boolean)value) ? 15 : 12;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value is Int32 && (Int32) value == 15;
}
}
// 將布林值轉成字體色刷
public class BooleanToHighlightFontColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (value is Boolean && (Boolean)value) ? new SolidColorBrush(Colors.AliceBlue) : new SolidColorBrush(Colors.Black);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
SolidColorBrush brush = value as SolidColorBrush;
return brush.Color == Colors.AliceBlue;
}
}
同時將 DataItem 改成更乾淨的 Model
public class DataItem : INotifyPropertyChanged
{
private Boolean special;
public Boolean Special
{
get
{
return special;
}
set
{
special = value;
NotifyPropertyChange("Special");
}
}
private String header;
public String Header
{
get
{
return header;
}
set
{
header = value;
NotifyPropertyChange("Header");
}
}
private String text;
public String Text
{
get
{
return text;
}
set
{
text = value;
NotifyPropertyChange("Text");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChange(String propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
在 MainWindow.xaml 中加入剛才建立的三個 Converter 為靜態資源,並將列表中照剛才的描述套用上合適的 Converter 如下
<Window x:Class="ConverterPractice.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ConverterPractice"
Title="MainWindow" Height="350" Width="150">
<Window.Resources>
<local:BooleanToHighlightBackgroundConverter x:Key="BackgroundConverter" />
<local:BooleanToHighlightFontSizeConverter x:Key="FontSizeConverter" />
<local:BooleanToHighlightFontColorConverter x:Key="FontColorConverter" />
</Window.Resources>
<Grid>
<ListBox ItemsSource="{Binding Items}" HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.Background>
<SolidColorBrush Color="{Binding Special, Converter={StaticResource BackgroundConverter}}" />
</Grid.Background>
<TextBlock Grid.Row="0" Text="{Binding Header}"
Foreground="{Binding Special, Converter={StaticResource FontColorConverter}}"
FontSize="{Binding Special, Converter={StaticResource FontSizeConverter}}" />
<TextBlock Grid.Row="1" Text="{Binding Text}"
Foreground="{Binding Special, Converter={StaticResource FontColorConverter}}"
FontSize="{Binding Special, Converter={StaticResource FontSizeConverter}}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
最後我撰寫一個 Timer 來每秒改變 Highlight 項目作為示範
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
items = new List<DataItem>();
items.Add(new DataItem { Special = false, Header = "Header A", Text = "Text A" });
items.Add(new DataItem { Special = false, Header = "Header B", Text = "Text B" });
items.Add(new DataItem { Special = false, Header = "Header C", Text = "Text C" });
items.Add(new DataItem { Special = false, Header = "Header D", Text = "Text D" });
items.Add(new DataItem { Special = false, Header = "Header E", Text = "Text E" });
items.Add(new DataItem { Special = false, Header = "Header F", Text = "Text F" });
DataContext = this;
timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromSeconds(1.0);
timer.Tick += OnTimerTick;
timer.Start();
}
private void OnTimerTick(object sender, EventArgs e)
{
Int32 highlightIndex = (DateTime.UtcNow.Second % 6);
for (Int32 i = 0; i < 6; ++i)
{
items[i].Special = i == highlightIndex;
}
}
private DispatcherTimer timer;
private List<DataItem> items;
public List<DataItem> Items
{
get
{
return items;
}
}
}
使用 Converter 後存放資料的類別更乾淨了,需要改變項目外觀時,也不需在多個地方調整,僅需調整對應的 Converter 即可,效果如下
沒有留言:
張貼留言