用Silverlight打造位运算器(2)--制作数字文本框控件

上一篇文章中,我们介绍了如何制作一个简易工具条,要完成位运算器,还需要一个很重要的控件,就是放数字的编辑框。在我的构想中这个编辑框所拥有以下功能:
1、 不允许输入非法字符,如十进制时只能输入数字0-9和负号。
2、 可以很方便地在各个进制间进行转换。
      关于第1点,最完美的解决方案就是在KeyDown事件中过滤字符,然后使用e.Handle=true方法来通知编辑框不再处理这次键盘按下事件,它最大的优点在于光标位置不会改变,但这个方法无法解决字符串粘贴时所带的非法字符。本来我想在TextChanged事件中做同样的处理,结果发现TextChanged事件中没有e.Handle参数,一查帮助,发现这个事件是异步事件,无法终止。上网找,中文资料,英文资料都找了,没找到合适的解决方案。最后没办法,只好自己在TextChanged事件里解决了。判断非法字符使用了正则表达式,以前不知道正则表达式,这里写得很痛苦,现在安逸多了。但总体来说,解决得并不是很完美,发生异常时光标无法定位在原来的位置,应该可以在SelectionChanged事件里解决这个问题,不过并未尝试,期待哪位大侠能给出完美的解决方案。
      写这个控件时遇到的第二个问题是如果在控件的TextChanged事件里抛出异常,我居然不知道在哪里可以捕捉这些异常,有点诡异,还是期待有人能给出答案。没办法,如果不处理这些异常,用户在狂按键盘都无法输入字符时可能会认为我的程序挂掉了。只好另辟蹊径,在编辑框控件上方安装一个简易的弹出式消息框,这样做不是很规范,但先把问题解决了再说。这里还有一个问题未解决,就是如何计算一个字符串所占用的像素长度,学习有时就是这么痛苦!
      这个控件完成后,我又发现了一个非常严重的问题:工具条在载入浏览器后无法使其中一个按钮处于按下状态,我的猜测是SpeedButton使用模板显示其外观,在载入窗体进行绘制时,必须按照默认状态进行绘制,对此我束手无策,还是希望有高手能给出答案。现在我能想出的解决办法就是不使用模板来显示外观,重写SpeedButton,这个留到下篇文章一起完成吧。
好,先来看看效果,这里需要注意,必须安装Silverlight 3.0版本才能正常运行示例。

请注意,工具条的BCD按钮本应该是处于按下状态的。
制作步骤:
1、在【BitLibrary】项目上单击鼠标右键,选择【添加】【新建项】,添加一个Silverlight用户控件,并命名为“BitTextBox.xaml”。更改BitTextBox.xaml文件如下:

 

<UserControl x:Class="BitLibrary.BitTextBox"
    xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml">
    
<Canvas x:Name="LayoutRoot" Height="47" Width="335">
        
<TextBox x:Name="BitTxt" Text="0" FontSize="16" TextAlignment="Right" 
                 Canvas.Left
="0" Canvas.Top="17" Height="30" Width="335" AcceptsReturn="False"/>
        
<Border x:Name="TipBorder" Canvas.Top="0" Canvas.Left="60" Height="18" Width="275" BorderBrush="Red"
                BorderThickness
="2" Background="#00ffffff" Visibility="Collapsed">
            
<Border.Resources>
                
<Storyboard x:Name="Story" Completed="Story_Completed">
                    
<ColorAnimationUsingKeyFrames Storyboard.TargetName="TipBorder"                                                  Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)">
                        
<DiscreteColorKeyFrame Value="#FF718597" KeyTime="00:00:0.5" />
                        
<DiscreteColorKeyFrame Value="Red" KeyTime="00:00:1" />
                        
<DiscreteColorKeyFrame Value="#FF718597" KeyTime="00:00:1.5" />
                        
<DiscreteColorKeyFrame Value="Red" KeyTime="00:00:2" />
                    
</ColorAnimationUsingKeyFrames>
                    
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="TipBorder"
                                     Storyboard.TargetProperty
="Opacity">
                        
<DiscreteDoubleKeyFrame Value="1" KeyTime="0:0:3"/>
                        
<LinearDoubleKeyFrame Value="0" KeyTime="0:0:4" />
                    
</DoubleAnimationUsingKeyFrames>
                
</Storyboard>
            
</Border.Resources>
            
<TextBlock x:Name="TxtMsg" TextAlignment="Right"/>
        
</Border>
    
</Canvas>
</UserControl>

     这里在Canvas上方是一个Border内含TextBlock,TextBlock用于显示异常信息,Border显示动画,也就是闪两下,然后消失。Canvas下方是编辑框控件,用于显示二到十六进制的数字。
2、打开BitTextBox.xaml.cs文件,更改代码如下:

 

  1 public partial class BitTextBox : UserControl
  2     {
  3         //二进制到十六进制的正则表达式
  4         const string BIN_EXPRESSION = "^[0-1]*$";
  5         const string OCT_EXPRESSION = "^[0-7]*$";
  6         const string BCD_EXPRESSION = "^[0-9-][0-9]*$";
  7         const string HEX_EXPRESSION = "^[a-f0-9A-F]*$";
  8         public BitTextBox()
  9         {
 10             InitializeComponent();
 11             BitTxt.TextChanged += new TextChangedEventHandler(BitTxt_TextChanged);
 12         }
 13         //声明依赖属性Text
 14         public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
 15             "Text"typeof(string), typeof(BitTextBox), null);
 16         public string Text
 17         {
 18             get { return BitTxt.Text; }
 19             set { Value = Convert.ToInt32(value, (int)state); }
 20         }
 21 
 22         string CurrentRegular = BCD_EXPRESSION;//记录当前所使用的正则表达式
 23         int value;
 24         public int Value//编辑框内所表示的整数值
 25         {
 26             get { return this.value; }
 27             set
 28             {
 29                 this.value = value;
 30                 SetTextFromValue();
 31             }
 32         }
 33         bool fillZero = true;
 34         public bool FillZero //指示,当显示为二进制时,高位不足处是否填充0
 35         {
 36             get { return fillZero; }
 37             set
 38             {
 39                 fillZero = value;
 40                 if (state == SystemState.Bin)
 41                 {
 42                     SetTextFromValue();
 43                 }
 44             }
 45         }
 46         SystemState state = SystemState.Bcd;//编辑框的当前进制状态
 47         public SystemState State
 48         {
 49             get { return state; }
 50             set
 51             {
 52                 if (state == value) return;
 53                 switch (value)
 54                 {
 55                     case SystemState.Bin:
 56                         CurrentRegular = BIN_EXPRESSION;
 57                         break;
 58                     case SystemState.Oct:
 59                         CurrentRegular = OCT_EXPRESSION;
 60                         break;
 61                     case SystemState.Bcd:
 62                         CurrentRegular = BCD_EXPRESSION;
 63                         break;
 64                     case SystemState.Hex:
 65                         CurrentRegular = HEX_EXPRESSION;
 66                         break;
 67                 }
 68                 //转换进制
 69                 state = value;
 70                 SetTextFromValue();
 71             }
 72         }
 73         //显示错误提示
 74         public void ShowTip(string msg) 
 75         {
 76             TxtMsg.Text = msg;
 77             TipBorder.Visibility = Visibility.Visible;
 78             TipBorder.Opacity = 1;
 79             Story.Begin();
 80         }
 81         private void Story_Completed(object sender, EventArgs e)
 82         {
 83             TipBorder.Visibility = Visibility.Collapsed;
 84         }
 85         //清空编辑框内的数字
 86         public void Clear()
 87         {
 88             Value = 0;
 89             BitTxt.Focus();
 90             BitTxt.SelectionStart = 0;
 91             BitTxt.SelectionLength = 1;
 92         }
 93         void BitTxt_TextChanged(object sender, TextChangedEventArgs e)
 94         {
 95             string str = BitTxt.Text;
 96             if (str == "-" && state==SystemState.Bcd)
 97             {
 98                 return;
 99             }
100             //正则表达式验证
101             if (!Regex.IsMatch(str, CurrentRegular))
102             {
103                 SetTextFromValue();
104                 switch (state) //显示异常信息
105                 {
106                     case SystemState.Bin:
107                         ShowTip("只能输入数字“0”和“1”");
108                         break;
109                     case SystemState.Oct:
110                         ShowTip("只能输入0~7之间的数字");
111                         break;
112                     case SystemState.Bcd:
113                         ShowTip("只能输入0~9之间的数字");
114                         break;
115                     case SystemState.Hex:
116                         ShowTip("只能输入数字0~9和字母a~f");
117                         break;
118                 }
119                 return;
120             }
121             //出现空白时
122             if (str == "")
123             {
124                 value = 0;
125                 BitTxt.Text = "0";
126                 return;
127             }
128             //防止数字超出int32所能容纳的范围
129             try
130             {
131                 int i = Convert.ToInt32(str, (int)state);
132             }
133             catch
134             {
135                 SetTextFromValue();
136                 ShowTip("您所输入的数字超出了32位有符号整数所能承受的范围");
137                 return;
138             }
139             value = Convert.ToInt32(str, (int)state);
140             BitTxt.Text = str.ToUpper();
141         }
142         //将值变成相应进制的字符串并赋给文本框
143         void SetTextFromValue()
144         {
145             string temp = Convert.ToString(this.value, (int)state).ToUpper();
146             if (state == SystemState.Bin && fillZero)
147             {
148                 temp = temp.PadLeft(32'0');
149             }
150             BitTxt.Text = temp;
151         }
152 }

这里声明了一个依赖属性Text,因为需要在Xaml文件中直接给编辑框赋文本值。如果你想在Xaml文件中调用其他文件,也可以声明它的依赖属性。
3、 更改MainPage.xaml代码如下:

<UserControl x:Class="BitCalculator.MainPage"
    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="470" d:DesignHeight="70">
    
<Canvas x:Name="LayoutRoot" Background="Goldenrod">
        
<src:ToolBar x:Name="toolBar" Grid.Row="1" SelectionChange="toolBar_SelectionChange"
                     Canvas.Left
="10" Canvas.Top="17"/>
        
<src:BitTextBox x:Name="txtBox" Text="20091122" Canvas.Left="132" Canvas.Top="0"/> 
        
<CheckBox x:Name="cbFillZero" Content="二进制数字不足32位补0" IsChecked="true"
                  Canvas.Left
="132" Canvas.Top="52" Click="cbFillZero_Click"/>
    
</Canvas>
</UserControl>

 4、 打开MainPage.xaml.cs,更改代码如下:

 

 1 public partial class MainPage : UserControl
 2 {
 3         public MainPage()
 4         {
 5             InitializeComponent();
 6         }
 7 
 8         private void toolBar_SelectionChange(object sender, RoutedEventArgs e)
 9         {
10             txtBox.State = toolBar.ToolState;
11         }
12 
13         private void cbFillZero_Click(object sender, RoutedEventArgs e)
14         {
15             if (txtBox != null)
16             {
17                 txtBox.FillZero = !txtBox.FillZero;
18             }
19         }
20 }

现在一个位运算器的雏形已经完成,可以在这个程序里进行进制转换。虽然现在还带着很多的疑惑,但学习的乐趣就在于此,发现问题,解决问题,获取知识和经验。

 


 

posted @ 2009-11-23 10:42  abatei  阅读(2076)  评论(1编辑  收藏  举报