代码改变世界

Silverlight学习点滴之二——为RadioButton换上新衣

2011-07-17 23:09  贼寇在何方  阅读(3900)  评论(12编辑  收藏  举报

WPF/Silverlight有个叫做模板的东西,可以为控件创建自定义的样式。

比如,有一组RadioButton(俗称“单选框”),在WrapPanel中自由排列,如下图的样子: 

 

打算山寨一下淘宝网的界面,做成这样:

 

开始折腾···



创建UserControl

自定义的用户控件,也就是图中“数据生成时间”以及下方的RadioButton。
取名FilterBox,布局很简单,Grid上方是一个标题,下方WrapPanel:

<UserControl>
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="35*"/>
<RowDefinition Height="91*"/>
</Grid.RowDefinitions>
<toolkit:WrapPanel Name="wrap" Grid.Row="1" Margin="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
</toolkit:WrapPanel>
<TextBlock Name="title" Margin="0" Height="Auto" Text="标题" HorizontalAlignment="Center" VerticalAlignment="Center">
</TextBlock>
</Grid>
</UserControl>

WrapPanel能够让他的Children横向排列,一行排满之后,会自动换行,用在这里是在适合不过了。



创建样式

选中的RadioButton样式可以看成一个粗边框+右下角的一个三角形;未选中的则用一个细的边框表示。

在UserControl下面增加Resources属性:

<Control.Resources>
<!--控件模板,Key为必需,并且设定目标类型为RadioButton-->
<ControlTemplate x:Key="Checked" TargetType="RadioButton">
<Grid>
<!--选中状态:粗边框-->
<Border Margin="1" BorderBrush="Blue" BorderThickness="2" Padding="4,1,4,0">
<!--内部的文字内容绑定了RadioButton的Content属性-->
<TextBlock Text="{TemplateBinding ContentControl.Content}"/>
</Border>
<!--三角形用Polygon表示-->
<Polygon Margin="1" Points="10,1 10,10 0,10" HorizontalAlignment="Right" VerticalAlignment="Bottom">
<Polygon.Fill>
<SolidColorBrush Color="Blue"/>
</Polygon.Fill>
</Polygon>
</Grid>
</ControlTemplate>
<ControlTemplate x:Key="UnChecked" TargetType="RadioButton">
<Grid>
<!--未选中状态:细边框-->
<Border Margin="2" BorderBrush="Gray" BorderThickness="1" Padding="4,1,4,0">
<TextBlock Text="{TemplateBinding ContentControl.Content}"/>
</Border>
</Grid>
</ControlTemplate>
</Control.Resources>

 

在WrapPanel中添加两个RadioButton,分别设定两种不同样式,转到设计界面查看效果:

<toolkit:WrapPanel Name="wrap" Grid.Row="1" HorizontalAlignment="Stretch" Margin="0" VerticalAlignment="Stretch">
<RadioButton Content="Checked" Template="{StaticResource Checked}"/>
<RadioButton Content="UnChecked" Template="{StaticResource UnChecked}"/>
</toolkit:WrapPanel>



实现

在实际使用中,需要动态添加RadioButton。
在WPF中,可以使用Setter样式,对控件某个属性的不同状态设定不同的样式(即选择不同的模板);而在Silverlight中,Setter是不被支持的,所以只能编写C#代码实现:

publicpartialclass FilterBox : UserControl
{
publicstring Title { get { return title.Text; } }

publicstring SelectedValue { get; privateset; }

publicevent RoutedEventHandler CheckChanged;

public FilterBox()
{
InitializeComponent();
}

public FilterBox(string name, IEnumerable<string> values)
{
InitializeComponent();
this.title.Text = name;

// 添加“全部”选择项
var c = CreateItem("全部");
c.IsChecked
=true;
this.wrap.Children.Add(c);
this.SelectedValue = c.Content asstring;

// 添加一般选择项
foreach (var i in values)
this.wrap.Children.Add(CreateItem(i));
}

privatevoid WhenCheckChanged(object sender, RoutedEventArgs e)
{
var c
= sender as RadioButton;
var isChecked
= c.IsChecked ??false;
// 依据IsChecked属性值选择模板
c.Template = Resources[isChecked ?"Checked" : "UnChecked"] as ControlTemplate;

if (isChecked)
{
this.SelectedValue = c.Content asstring;
// 触发CheckChanged事件,以便外部代码访问
if (CheckChanged !=null)
CheckChanged(
this, null);
}
}

// 创建新的单选项
private RadioButton CreateItem(string item)
{
var radio
=new RadioButton();
radio.Content
= item;
// 设定缺省的UnChecked模板
radio.Template =this.Resources["UnChecked"] as ControlTemplate;
// 订阅事件
radio.Checked += WhenCheckChanged;
radio.Unchecked
+= WhenCheckChanged;
return radio;
}
}

 

接着创建一个ChildWindow用户控件,取名ChildWindowX。在Loaded事件响应方法中创建FilterBox:

privatevoid ChildWindow_Loaded(object sender, RoutedEventArgs e)
{
LayoutRoot.Children.Add(
new FilterBox("数据生成时间",
newstring[] { "更早", "2006", "2007", "2008", "2009", "2010", "2011" }));
}



运行,看下效果: