用Silverlight打造位运算器(3)--完成
上一回我们说到,使用模板制作的SpeedButton无法在载入浏览器时处于按下状态,这个缺点是我无法忍受的,没办法,只好使用用户控件的方式重写SpeedButton以解决这个问题。所有控件完成后,位移运算器就变得十分简单了。没想到当年要3000行代码完成的东西,变得如此简单,有些超出我的预期。
好,先看看位移运算器的完整效果,请首先安装Silverlight3.0
最新发现不登录博客园的用户无法直接看到Silverlight,如果是这样,请移步到以下网址观看动画:
http://www.bbniu.com/matrix/ShowApplication.aspx?id=147
界面做成这样,主要是考虑到可以用它来上课做演示,很多计算机课程都需要讲到位运算。
制作步骤:
一、 重写SpeedButton
1、 在BitLibrary中删除Theme文件夹及SpeedButton.cs文件。
2、 在【BitLibrary】项目上单击鼠标右键,选择【添加】【新建项】,添加一个Silverlight用户控件,并命名为“SpeedButton.xaml”。更改SpeedButton.xaml文件如下:
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<UserControl.Resources>
<LinearGradientBrush x:Key="BorderNormalBrush">
<GradientStop Color="#FFA3AEB9" Offset="0"/>
<GradientStop Color="#FF8399A9" Offset="0.375"/>
<GradientStop Color="#FF718597" Offset="0.375"/>
<GradientStop Color="#FF617584" Offset="1"/>
</LinearGradientBrush>
<SolidColorBrush x:Key="BorderBgPressedBrush" Color="#FF6DBDD1"/>
<SolidColorBrush x:Key="BorderBgNormaldBrush" Color="White"/>
<LinearGradientBrush x:Key="RectNormalBrush" StartPoint=".7,0" EndPoint=".7,1">
<GradientStop Color="#FFFFFFFF" Offset="0" />
<GradientStop Color="#F1FFFFFF" Offset="0.375" />
<GradientStop Color="#DCFFFFFF" Offset="0.625" />
<GradientStop Color="#8FFFFFFF" Offset="1" />
</LinearGradientBrush>
<LinearGradientBrush x:Key="RectMouseOverBrush" StartPoint=".7,0" EndPoint=".7,1">
<GradientStop Color="#FFFFFFFF" Offset="0" />
<GradientStop Color="#C2FFFFFF" Offset="0.375" />
<GradientStop Color="#8CFFFFFF" Offset="0.625" />
<GradientStop Color="#C8FFFFFF" Offset="1" />
</LinearGradientBrush>
<LinearGradientBrush x:Key="RectPressedBrush" StartPoint=".7,0" EndPoint=".7,1">
<GradientStop Color="#D8FFFFFF" Offset="0" />
<GradientStop Color="#C6FFFFFF" Offset="0.375" />
<GradientStop Color="#8CFFFFFF" Offset="0.625" />
<GradientStop Color="#3FFFFFFF" Offset="1" />
</LinearGradientBrush>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="Transparent" Width="30" Height="30">
<Border x:Name="Bd" CornerRadius="3" Background="{StaticResource BorderBgNormaldBrush}" BorderThickness="1"
BorderBrush="{StaticResource BorderNormalBrush}">
<Grid Background="Transparent" Margin="1">
<Border x:Name="BackgroundAnimation" Background="#FF448DCA"/>
<Rectangle x:Name="BackgroundGradient" Fill="{StaticResource RectNormalBrush}"/>
</Grid>
</Border>
<ContentPresenter x:Name="contentPresenter" VerticalAlignment="Center"
HorizontalAlignment="Center" Margin="0"/>
</Grid>
</UserControl>
在这个SpeedButton里使用了跟之前模板里一样的外观,不同之处是在控件的资源内添加了6种画刷,这些静态资源不但可以直接在xaml文件中使用StaticResource关键字进行引用,也可以在cs文件中使用this. Resources["资源名称"]进行引用,从而可以很方便地改变控件外观。
3、 打开SpeedButton.xaml.cs文件,更改代码如下:
2 {
3 public SpeedButton()
4 {
5 InitializeComponent();
6 this.MouseEnter += new MouseEventHandler(SpeedButton_MouseEnter);
7 this.MouseLeave += new MouseEventHandler(SpeedButton_MouseLeave);
8 this.MouseLeftButtonDown += new MouseButtonEventHandler(SpeedButton_MouseLeftButtonDown);
9 }
10 //声明依赖属性Text
11 public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
12 "Text", typeof(string), typeof(SpeedButton), null);
13 public string Text
14 {
15 get { return (string)contentPresenter.Content; }
16 set { contentPresenter.Content = value; }
17 }
18 public SystemState State
19 {
20 get;
21 set;
22 }
23 private Boolean isPress = false; //指示按钮是否处于按下状态
24 public Boolean IsPress
25 {
26 get
27 {
28 return isPress;
29 }
30 set
31 {
32 if (IsPress == value) return;
33 isPress = value;
34 if (isPress)
35 {
36 Bd.Background = (SolidColorBrush)Resources["BorderBgPressedBrush"];
37 BackgroundGradient.Fill = (LinearGradientBrush)Resources["RectPressedBrush"];
38 }
39 else
40 {
41 Bd.Background = (SolidColorBrush)Resources["BorderBgNormaldBrush"];
42 BackgroundGradient.Fill = (LinearGradientBrush)Resources["RectNormalBrush"];
43 }
44 }
45 }
46 void SpeedButton_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
47 {
48 if (!isPress)
49 {
50 IsPress = true;
51 }
52 }
53
54 void SpeedButton_MouseLeave(object sender, MouseEventArgs e)
55 {
56 if (!isPress)
57 {
58 BackgroundGradient.Fill = (LinearGradientBrush)Resources["RectNormalBrush"];
59 }
60 }
61
62 void SpeedButton_MouseEnter(object sender, MouseEventArgs e)
63 {
64 if (!isPress)
65 {
66 BackgroundGradient.Fill = (LinearGradientBrush)Resources["RectMouseOverBrush"];
67 }
68 }
69 }
大家应该也会注意到,之前在模板中,外观的改变使用的是动画,但所有的动画时间(Duration)都为0。而在现在这个SpeedButton控件中,通过直接更改画刷来改变控件外观,这些更改都是在鼠标事件中实现的。虽然实现不同,但效果是一样的。运行程序,我们发现OCT按钮是处于按下状态的。终于解决了这个大bug。
大家可以对比相同控件两种不同的做法,使用模板控件从ContentControl控件继承,而使用用户控件需要从UserControl进行继承,这样很多放在UserControl里的控件的属性就会被屏敝掉,从而不能再调用Content属性对按钮上显示的文字进行设置。如本例所示,声明了一个依赖属性Text来对按钮上的文字进行设置。
经过以上努力,终于可以开始写位移运算器了,当然,没遇到任何困难,如砍瓜切菜般,迅速完成。唯一不爽的地方是VS2008里使用SL3没有界面设计窗口,要不停地运行程序来看控件位置,有点郁闷。
二、位运算器主程序
1、更改MainPage.xaml代码如下:
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:src="clr-namespace:BitLibrary;assembly=BitLibrary"
mc:Ignorable="d" d:DesignWidth="569" d:DesignHeight="195">
<Canvas x:Name="LayoutRoot" Background="SkyBlue" Loaded="LayoutRoot_Loaded">
<src:ToolBar x:Name="tbTop" Grid.Row="1" SelectionChange="tb_SelectionChange"
Canvas.Left="10" Canvas.Top="17"/>
<src:BitTextBox x:Name="btxtTop" Text="20091122" Canvas.Left="132" Canvas.Top="0"/>
<Button x:Name="btnTopSHL" Content="<<" Canvas.Left="469" Canvas.Top="17" Width="30" Height="30" ToolTipService.ToolTip="左移" Click="SHL_Click" />
<Button x:Name="btnTopSHR" Content=">>" Canvas.Left="499" Canvas.Top="17" Width="30" Height="30" ToolTipService.ToolTip="右移" Click="SHR_Click"/>
<Button x:Name="btnTopNOT" Content="~" Canvas.Left="529" Canvas.Top="17" Width="30" Height="30" ToolTipService.ToolTip="求补" Click="NOT_Click"/>
<src:ToolBar x:Name="tbMid" Grid.Row="1" SelectionChange="tb_SelectionChange"
Canvas.Left="10" Canvas.Top="49"/>
<src:BitTextBox x:Name="btxtMid" Text="20091122" Canvas.Left="132" Canvas.Top="32"/>
<Button x:Name="btnMidSHL" Content="<<" Canvas.Left="469" Canvas.Top="49" Width="30" Height="30" ToolTipService.ToolTip="左移" Click="SHL_Click"/>
<Button x:Name="btnMidSHR" Content=">>" Canvas.Left="499" Canvas.Top="49" Width="30" Height="30" ToolTipService.ToolTip="右移" Click="SHR_Click"/>
<Button x:Name="btnMidNOT" Content="~" Canvas.Left="529" Canvas.Top="49" Width="30" Height="30" ToolTipService.ToolTip="求补" Click="NOT_Click"/>
<Button x:Name="btnAnd" Content="AND" Canvas.Left="235" Canvas.Top="81" Width="30" Height="30" ToolTipService.ToolTip="与运算" Click="btnAnd_Click"/>
<Button x:Name="btnOr" Content="OR" Canvas.Left="265" Canvas.Top="81" Width="30" Height="30" ToolTipService.ToolTip="或运算" Click="btnOr_Click"/>
<Button x:Name="btnXor" Content="XOR" Canvas.Left="295" Canvas.Top="81" Width="30" Height="30" ToolTipService.ToolTip="异或运算" Click="btnXor_Click"/>
<Button x:Name="btnMod" Content="MOD" Canvas.Left="325" Canvas.Top="81" Width="30" Height="30" ToolTipService.ToolTip="取模" Click="btnMod_Click"/>
<Button x:Name="btnClear" Content="CLR" Canvas.Left="355" Canvas.Top="81" Width="30" Height="30" ToolTipService.ToolTip="清空文框" Click="btnClear_Click"/>
<src:ToolBar x:Name="tbBottom" Grid.Row="1" SelectionChange="tb_SelectionChange"
Canvas.Left="10" Canvas.Top="113"/>
<src:BitTextBox x:Name="btxtBottom" Text="20091122" Canvas.Left="132" Canvas.Top="96"/>
<Button x:Name="btnBottomSHL" Content="<<" Canvas.Left="469" Canvas.Top="113" Width="30" Height="30" ToolTipService.ToolTip="左移" Click="SHL_Click"/>
<Button x:Name="btnBottomSHR" Content=">>" Canvas.Left="499" Canvas.Top="113" Width="30" Height="30" ToolTipService.ToolTip="右移" Click="SHR_Click"/>
<Button x:Name="btnBottomNOT" Content="~" Canvas.Left="529" Canvas.Top="113" Width="30" Height="30" ToolTipService.ToolTip="求补" Click="NOT_Click"/>
<CheckBox x:Name="cbFillZero" Content="二进制数字不足32位补0" IsChecked="true"
Canvas.Left="10" Canvas.Top="150" Click="cbFillZero_Click"/>
<CheckBox x:Name="cbAllCtrl" Content="统一进制控制" IsChecked="false"
Canvas.Left="165" Canvas.Top="150" Click="cbAllCtrl_Click"/>
<TextBlock Text="http://www.cnblogs.com/abatei" Canvas.Top="168" Canvas.Left="10"/>
</Canvas>
</UserControl>
2、打开MainPage.xaml.cs文件,更改代码如下:
2
3 namespace BitCalculator
4 {
5 public partial class MainPage : UserControl
6 {
7 public MainPage()
8 {
9 InitializeComponent();
10 }
11
12
13 private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
14 {
15 tbTop.Tag = btxtTop;
16 tbMid.Tag = btxtMid;
17 tbBottom.Tag = btxtBottom;
18 btnTopSHL.Tag = btxtTop;
19 btnTopSHR.Tag = btxtTop;
20 btnTopNOT.Tag = btxtTop;
21 btnMidSHL.Tag = btxtMid;
22 btnMidSHR.Tag = btxtMid;
23 btnMidNOT.Tag = btxtMid;
24 btnBottomSHL.Tag = btxtBottom;
25 btnBottomSHR.Tag = btxtBottom;
26 btnBottomNOT.Tag = btxtBottom;
27 }
28
29 private void cbFillZero_Click(object sender, RoutedEventArgs e)
30 {
31 btxtTop.FillZero = (bool)cbFillZero.IsChecked;
32 btxtMid.FillZero = (bool)cbFillZero.IsChecked;
33 btxtBottom.FillZero = (bool)cbFillZero.IsChecked;
34 }
35
36 private void tb_SelectionChange(object sender, RoutedEventArgs e)
37 {
38 SystemState state=((ToolBar)sender).ToolState;
39 if ((bool)cbAllCtrl.IsChecked)
40 {
41 btxtTop.State = state;
42 btxtMid.State = state;
43 btxtBottom.State = state;
44 }
45 else
46 {
47 ((BitTextBox)((ToolBar)sender).Tag).State = state;
48 }
49 }
50
51 private void SHL_Click(object sender, RoutedEventArgs e)
52 {
53 BitTextBox btxt = (BitTextBox)((Button)sender).Tag;
54 btxt.Value = btxt.Value << 1;
55 }
56
57 private void SHR_Click(object sender, RoutedEventArgs e)
58 {
59 BitTextBox btxt = (BitTextBox)((Button)sender).Tag;
60 btxt.Value = btxt.Value >> 1;
61 }
62
63 private void NOT_Click(object sender, RoutedEventArgs e)
64 {
65 BitTextBox btxt = (BitTextBox)((Button)sender).Tag;
66 btxt.Value = ~btxt.Value;
67 }
68
69 private void btnAnd_Click(object sender, RoutedEventArgs e)
70 {
71 btxtBottom.Value = btxtTop.Value & btxtMid.Value;
72 }
73
74 private void btnOr_Click(object sender, RoutedEventArgs e)
75 {
76 btxtBottom.Value = btxtTop.Value | btxtMid.Value;
77 }
78
79 private void btnXor_Click(object sender, RoutedEventArgs e)
80 {
81 btxtBottom.Value = btxtTop.Value ^ btxtMid.Value;
82 }
83
84 private void btnMod_Click(object sender, RoutedEventArgs e)
85 {
86 btxtBottom.Value = btxtTop.Value % btxtMid.Value;
87 }
88
89 private void btnClear_Click(object sender, RoutedEventArgs e)
90 {
91 btxtTop.Clear();
92 btxtMid.Clear();
93 btxtBottom.Clear();
94 }
95
96 private void cbAllCtrl_Click(object sender, RoutedEventArgs e)
97 {
98 if ((bool)cbAllCtrl.IsChecked)
99 {
100 tbTop.Visibility = Visibility.Collapsed;
101 btxtTop.State = tbMid.ToolState;
102 tbBottom.Visibility = Visibility.Collapsed;
103 btxtBottom.State = tbMid.ToolState;
104 }
105 else
106 {
107 tbTop.Visibility = Visibility.Visible;
108 tbTop.ToolState = btxtTop.State;
109 tbBottom.Visibility = Visibility.Visible;
110 tbBottom.ToolState = btxtBottom.State;
111 }
112 }
113 }
114 }
位运算器完成后,我马上把成果用在了其他地方,在之前做的Hashtable动态演示程序中加入了位运算编辑框,这样在选中一个结点时,可以通过这个编辑框查看结点哈希码的不同进制的数字。
演示地址:http://www.cnblogs.com/abatei/archive/2009/06/23/1509790.html