色選択リストを作る
Silverlightで色を選択するためのリストが欲しかったので作ってみた。
普通ならComboBoxを使って、テンプレートを変更すればいいんだろうけど、現状のBeta2ではまだ用意されていない(というか正式版では用意されるんだよね?)ので、色々ごちゃごちゃ組み合わせてやってみた。
ColorPicker.xaml
<UserControl x:Class="SilverlightApplication1.ColorPicker" xmlns="http://schemas.microsoft.com/client/2007" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Loaded="UserControl_Loaded"> <StackPanel Background="White"> <Border x:Name="colorBlock" Height="25" Margin="0,0,0,1" BorderThickness="1" BorderBrush="Black"> <Button x:Name="dropButton" Width="20" Click="dropButton_Click" HorizontalAlignment="Right"> <Button.Template> <ControlTemplate> <Grid> <Rectangle Fill="Silver" Width="20" /> <Polygon Points="0,0,12,0,6,6" Fill="Black" HorizontalAlignment="Center" VerticalAlignment="Center"> </Polygon> </Grid> </ControlTemplate> </Button.Template> </Button> </Border> <Canvas> <ListBox x:Name="colorList" Height="200" Visibility="Collapsed" SelectionChanged="colorList_SelectionChanged"> <ListBox.ItemTemplate> <DataTemplate> <Rectangle x:Name="colorRect" Fill="{Binding Brush}" Width="{Binding Width}" Height="20" Stroke="Black" StrokeThickness="0" MouseMove="colorRect_MouseMove" MouseLeave="colorRect_MouseLeave"> <Rectangle.Resources> <Storyboard x:Name="highlight"> <DoubleAnimation From="0" To="1" Duration="0" Storyboard.TargetName="colorRect" Storyboard.TargetProperty="StrokeThickness" /> </Storyboard> </Rectangle.Resources> </Rectangle> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </Canvas> </StackPanel> </UserControl>
他の要素にオーバーラップさせて表示するListBoxをCanvasの中に配置することで実現できたけど、このColorPickerコントロールよりあとに追加されたコントロールにはZIndexで負けてしまうので隠れてしまう。このへんはどう解消すればいいのかわからない。
ColorPicker.xaml.cs
using System; using System.Windows; using System.Windows.Input; using System.Windows.Media; using System.Windows.Controls; using System.Windows.Media.Animation; using System.Reflection; using System.Collections.Generic; using System.Diagnostics; namespace SilverlightApplication1 { /// <summary> /// 色の一覧リストから色を選択するComboBoxコントロール /// </summary> public partial class ColorPicker : UserControl { /// <summary> /// /// </summary> public class ColorPickerItem { /// <summary> /// ブラシを取得、設定します。 /// </summary> public Brush Brush { get; set; } /// <summary> /// 横幅を取得、設定します。 /// </summary> public double Width { get; set; } } /// <summary> /// 選択している色を取得します。 /// </summary> public Color? SelectedColor { get { SolidColorBrush brush = colorBlock.Background as SolidColorBrush; return brush != null ? (Color?)brush.Color : null; } } /// <summary> /// 選択している色が変更された時に呼び出されます。 /// </summary> public event RoutedEventHandler SelectedColorChanged; /// <summary> /// SelectedColorChangedイベントを発生させます。 /// </summary> /// <param name="e">イベント引数</param> protected virtual void OnSelectedColorChanged(RoutedEventArgs e) { if(SelectedColorChanged != null) SelectedColorChanged(this, e); } public ColorPicker() { InitializeComponent(); } private void UserControl_Loaded(object sender, RoutedEventArgs e) { var colors = new List<ColorPickerItem>(); foreach(var propInfo in typeof(Colors).GetProperties()) { if(propInfo.Name == "Transparent") continue; var color = (Color)propInfo.GetValue( null, BindingFlags.Static | BindingFlags.GetProperty, null, null, null ); colors.Add(new ColorPickerItem { Brush = new SolidColorBrush(color), Width = this.Width - 25 }); } colorList.ItemsSource = colors; } private void dropButton_Click(object sender, RoutedEventArgs e) { colorList.Visibility = (colorList.Visibility == Visibility.Visible) ? Visibility.Collapsed : Visibility.Visible; } private void colorList_SelectionChanged(object sender, SelectionChangedEventArgs e) { colorList.Visibility = Visibility.Collapsed; colorBlock.Background = ((ColorPickerItem)colorList.SelectedItem).Brush; OnSelectedColorChanged(new RoutedEventArgs { Source=this }); } private void colorRect_MouseMove(object sender, MouseEventArgs e) { ((Storyboard)((FrameworkElement)sender).FindName("highlight")).Begin(); } private void colorRect_MouseLeave(object sender, MouseEventArgs e) { ((Storyboard)((FrameworkElement)sender).FindName("highlight")).Stop(); } } }
スクリーンショット
見ての通り、まったくスマートじゃない。Silverlightを勉強するにあたってWPFをざっと勉強してみたけど、WPFと比べてSilverlightには足りない機能が多い。
特にデータバインディング関係とイベントトリガー関係。この二つがしょぼいおかげで、WPFならコードが要らないところが、Silverlightだとしょうもないコードを書く必要が生じてしまう。
正式版になったらこのへんは解消するんだろうか?じゃないとちょっと微妙な感じになってくるなぁ。