本篇讲解Button and Other Controls
在wpf中,控件一词比早期的window from更具有意义,在早期的windows from中,屏幕上的一切都是控件,但是在wpf中这个词保留给用户交互使用。也就是说,在用户使用键盘或者鼠标时,控件会给用户一定的响应。
Control类继承自FrameworkElement:
1: Object
2: DispatherObject(abstract)3: DependencyObject
4: Visual(abstract)5: UIElement
6: FrameworkElement
7: Control
最经典的控件是按钮,wpf中为Button类,Button类中有个一Content的propterty和一个为Click的Event,当用户按下鼠标时就会发生事件。
一个例子:
1: using System;2: using System.Collections.Generic;3: using System.Linq;4: using System.Text;5: using System.Windows;6: using System.Windows.Controls;7: using System.Windows.Data;8: using System.Windows.Documents;9: using System.Windows.Input;10: using System.Windows.Media;11: using System.Windows.Media.Imaging;12: using System.Windows.Navigation;13: using System.Windows.Shapes;14:
15: namespace WPF_ButtonAndControls16: {
17: /// <summary>18: /// MainWindow.xaml 的交互逻辑19: /// </summary>20: public partial class MainWindow : Window21: {
22: public MainWindow()23: {
24: InitializeComponent();
25: Loaded += MainWindowOnLoaded;
26: }
27:
28: private void MainWindowOnLoaded(object sender, RoutedEventArgs e)29: {
30: SimpleButton();
31: }
32:
33: private void SimpleButton()34: {
35: Button btn = new Button();36: btn.Content = "_Click Me,Please";37: btn.Click += (sender, e) =>
38: {
39: MessageBox.Show("Hello world!");40: };
41: Content = btn;
42: }
43: }
44: }
Button有一个Content属性,和window控件一样,并不是巧合,这两个类同时继承自ContentControl类,也就是定义Content property的地方。
1: Control
2: ContentControl
3: BaseButton(abstract)4: Button
5: Window
这样,能够被当作Window的Content的对象都可以作为Button的Content对象来使用。
该程序开始,Button并没有焦点(input focus)的,此时的按钮并不会接受键盘事件,比如你按下空格键时,程序并没有被执行,但是你可以通过按下ALT+C组合键来触发(Trigger)按钮,当你设置Content property字符串中的某个字符前加_符号,就会让此控件具有快捷键(ALT+字符),这个特点常常用于菜单中。
你可以在代码中用如下的方式来指定某个控件具有焦点:
1: btn.Focus();
即使按钮没有获得焦点,但是如果你设定它为默认控件,那么它依然可以对Enter键具有反应
1: btn.IsDefault=true;或者让它对Escape键有响应
1: btn.IsCancel=true;ButtonBase定义了一个名为ClickMode的Property,其类别为ClickMode枚举,用来指定按钮要如何反馈鼠标点击,默认值是ClickMode.Release;如果你设定其为ClickMode.Press或者ClickMode.Hover,那么会在鼠标按下或者经过时就触发事件。
1: btn.ClickMode = ClickMode.Hover;
FrameworkElement控件具有margin property,我们可以用这个属性来element周围有一点空间。
1: btn.Margin = new Thickness(96);
1: btn.HorizontalContentAlignment = System.Windows.HorizontalAlignment.Left;
2: btn.VerticalContentAlignment = System.Windows.VerticalAlignment.Bottom;
我们也可以加入内边距padding,代码如下:
1: btn.Padding = new Thickness(48);当然,Button的HorizontalContentAlignment和VerticalContentAlignment以及HorizontalAlignment和VerticalAlignment属性默认设置为HorizontalAlignment.Stretch和VerticalAlignment.Stretch这两个属性,这也是为什么按钮会被拉伸的原因。
现在我们删除其他的设定代码,只设定Button的HoriaontalAlignment和VerticalAlignment属性:
1: btn.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
2: btn.VerticalAlignment = System.Windows.VerticalAlignment.Center;
那么现在,你看到按钮已经被设定为Element的中央,并且符合Content的内容,当然你也可以插入换行符来进行测试。
另外,你也可以测试下window的SizeToContent property
1: SizeToContent = System.Windows.SizeToContent.WidthAndHeight;
当然你可以尝试的改变button的其他样式,例如
1: btn.Background = Brushes.CornflowerBlue;
2: btn.Foreground = Brushes.Yellow;
3: btn.BorderBrush = Brushes.Tomato;
我们来一个例子,演示button的关于MouseEnter和MouseLeave事件
1: private void TestButton()2: {
3: Run runButton = null;4: TextBlock tb = new TextBlock();5: tb.TextAlignment = TextAlignment.Center;
6: tb.FontSize = 24;
7:
8: Button btn = new Button();9: btn.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
10: btn.VerticalAlignment = System.Windows.VerticalAlignment.Center;
11: btn.MouseEnter += (sender, e) =>
12: {
13: runButton.Foreground = Brushes.Red;
14: };
15: btn.MouseLeave += (sender, e) =>
16: {
17: runButton.Foreground = SystemColors.ControlTextBrush;
18: };
19: //在textblock中加入格式化字符串20: tb.Inlines.Add(new Italic(new Run("Click")));21: tb.Inlines.Add(" the ");22: tb.Inlines.Add(runButton = new Run("Button"));23: tb.Inlines.Add(new LineBreak());24: tb.Inlines.Add("to launch the ");25: tb.Inlines.Add(new Bold(new Run("roket")));26:
27: btn.Content = tb;
28: Content = btn;
29: }
我们在使用一个图片来作为按钮的Content:
1: Uri uri = new Uri("pack://application:,,/images/filename");
1: private void ImageButton()
2: {
3: Button btn = new Button();
4: Uri uri = new Uri("pack://application:,,/Image/word.jpg");
5: BitmapImage bitmap = new BitmapImage(uri);
6: Image img = new Image();
7: img.Source = bitmap;
8: img.Stretch = Stretch.None;
9: btn.Content = img;
10: btn.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
11: btn.VerticalAlignment = System.Windows.VerticalAlignment.Center;
12: Content = btn;
13: }
现在我们讲解Comand property用法,这个想法来自于用一个单一点来路由所有监听响应控件的消息。对于常见的命令,你可以将button的command property属性设置为:ApplicationCommands、ComponentCommands、MediaCommands、NavigationCommands或EditingCommands类的静态property,你可以创建自己的RouteUICommand对象。
比如说,你想要特定的按钮进行Paster命令,你可以将Command property设定为这样:
1: btn.Content = ApplicationCommands.Paste.Text;
2: btn.Command = ApplicationCommands.Paste;
我们来看一个例子:
1: private void ButtonCommand()
2: {
3: Title = "Command the Button";
4: Button btn = new Button();
5: btn.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
6: btn.VerticalAlignment = System.Windows.VerticalAlignment.Center;
7: btn.Content = ApplicationCommands.Paste.Text;
8: btn.Command = ApplicationCommands.Paste;
9:
10: CommandBindings.Add(new CommandBinding(ApplicationCommands.Paste
11: , (sender, e) =>
12: {
13: Title = Clipboard.GetText();
14: }
15: , (sender, e) =>
16: {
17: e.CanExecute = Clipboard.ContainsText();
18: }));
19: Content = btn;
20: }
这个例子演示了一个button如何使用Command property,在UEElement类中定义了一个CommandBindings属性,我们使用了window类的Commandbindings property。这个例子中的Clipboard类属于System.Window命名空间,你可以复制一段文字,然后查看具体效果,然后在复制一张图片,在查看具体效果,你会发现,复制一张图片时,按钮会被禁用,这就是第二个事件中的e.CanExecute被设为false的原因,程序会自动判断,然后改变button的IsEnabled property,这就是使用Command propery的好处之一。
CheckBox和RadioButton都被认为是切换(toggle)按钮,这一点可以从继承树中查看。
1: Control
2: ContentControl
3: ButtonBase(abstract)
4: Button
5: GridViewColumnHeader
6: RepeatButton
7: ToggleButton
8: CheckBox
9: RadioButton
ToggleButton并不是抽象类,所以我们可以建立它的对象,它看起来和普通按钮一样,但是它具有on和off的切换,看一个例子:
1: private void ToggleButtonExmple()
2: {
3: ToggleButton tb = new ToggleButton();
4: tb.Content = "Can _Resize";
5: tb.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
6: tb.VerticalAlignment = System.Windows.VerticalAlignment.Center;
7: tb.IsChecked = (ResizeMode == System.Windows.ResizeMode.CanResize);
8: tb.Checked += TbOnCheck;
9: tb.Unchecked += TbOnCheck;
10: Content = tb;
11: }
12:
13: private void TbOnCheck(object sender,RoutedEventArgs e)
14: {
15: ToggleButton btn = sender as ToggleButton;
16: ResizeMode = (bool)btn.IsChecked ? ResizeMode.CanResize : System.Windows.ResizeMode.NoResize;
17: }
ToggleButton在这里不用来控制窗体的ResizeMode属性,在ResizeMode.CanResize和ResizeMode.NoResize中来回切换。
如果将ToggleButton的IsThreeState property设置为True,那么你可以使用ToggleButton的第三种状态null用来表示不确定的状态。
ToggleButton和CheckBox本质上都是代表bool值的,如果让togglebutton来和某个对象的某个bool值属性相关联是有意义的,这就被称为属性绑定,调用的方法:
1: tb.SetBinding(ToggleButton.IsCheckedProperty, "smoeproperty");
第二个参数是字符串,是你想要和按钮的IsCheck产生相关联的property名,你用button的datacontext property来指定someproperty的所属对象。
我们来修改上面的例子:
1: private void ToggleButtonExmple()
2: {
3: ToggleButton tb = new ToggleButton();
4: tb.Content = "Can _Resize";
5: tb.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
6: tb.VerticalAlignment = System.Windows.VerticalAlignment.Center;
7: //tb.IsChecked = (ResizeMode == System.Windows.ResizeMode.CanResize);
8: //tb.Checked += TbOnCheck;
9: //tb.Unchecked += TbOnCheck;
10: tb.SetBinding(ToggleButton.IsCheckedProperty, "Topmost");
11: tb.DataContext = this;
12: Content = tb;
13: }
这里我们让togglebutton和window的Topmost property属性关联,Topmost属性为True是,可以使window始终据与顶层,当你点击button的时候,这个属性也在随之改变。
在System.windows.Data命名空间中包含着一个叫Binding的类,你可以用这个类来设置属性绑定:
1: Binding bind = new Binding("Tommost");
2: bind.Source = this;
3: tb.SetBinding(ToggleButton.IsCheckedProperty, bind);