《WPF揭秘》学习随笔 01

  • XAML中实现鼠标移入按钮后按钮变化:
        <Button MinWidth="75" Margin="10">
                    <Button.Style>
                        <Style TargetType="{x:Type Button}">
                            <Style.Triggers>
                                <Trigger Property="IsMouseOver" Value="True">
                                    <Setter Property="Foreground" Value="Red"/>
                                </Trigger>
                            </Style.Triggers>
                        </Style>
                    </Button.Style>
                        OK
        </Button>
    
  • 在Debug环境中遍历并打印出逻辑树和可视树:
    public partial class AboutDialog : Window
    {
        public AboutDialog()
        {
            InitializeComponent();
            PrintLogicalTree(0, this);
        }
    
        protected override void OnContentRendered(EventArgs e)
        {
            base.OnContentRendered(e);
            PrintVisualTree(0, this);
        }
        
        void PrintLogicalTree(int depth, object obj)
        {
            // Print the object with preceding spaces that represent its depth
            Debug.WriteLine(new string(' ', depth) + obj);
            // Sometimes leaf nodes aren抰 DependencyObjects (e.g. strings)
            if (!(obj is DependencyObject)) return;
            // Recursive call for each logical child
            foreach (object child in LogicalTreeHelper.GetChildren(
            obj as DependencyObject))
                PrintLogicalTree(depth + 1, child);
        }
    
        void PrintVisualTree(int depth, DependencyObject obj)
        {
            // Print the object with preceding spaces that represent its depth
            Debug.WriteLine(new string(' ', depth) + obj);
            // Recursive call for each visual child
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
                PrintVisualTree(depth + 1, VisualTreeHelper.GetChild(obj, i));
        }
    }
    可视树直到Window完成至少一次布局之后才会有节点,否则是空的。这也是为什么PrintVisualTree是在OnContentRendered中调用的,因为OnContentRendered是在布局完成之后才被调用的。
  • 如果不设置整个Windows元素的FontSize和FontStyle,而是在内部的StackPanel上设置它们的话,这两个属性仅仅会被StackPanel下的控件继承。然而, 把属性特性移到内部的StackPanel元素中没有什么作用,因为StackPanel自己没有任何与字体相关的属性。相反,你必须使用FontSize和FontStyle附加属性,这是在一个叫作TextElement的类中定义的。如下:
    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" TextElement.FontSize="30">
    </StackPanel>

  • 类似于以往Windows Forms那样的技术,许多WPF类定义了一个Tag属性(类型是System.Object),目的是为了存储每一个实例的自定义数据。但是要添加自定义数据给任何一个派生自DependencyObject的对象,附加属性是一种更加强大、更加灵活的机制。通常我们会忽略一点,即你可以用附加属性高效地向密封类(sealed class)的实例添加自定义数据(WPF中到处都是密封类)。
    例如,FrameworkElement的Tag属性是一个依赖属性,因此可以把一个GeometryModel3D(它是一个密封类,没有Tag属性)的对象实例附加给它。
            GeometryModel3D model = new GeometryModel3D();
            model.SetValue(FrameworkElement.TagProperty, "My costom data");
    

  • 虽然在事件处理程序中设置RoutedEventArgs参数的Handled属性为true,可以终止管道传递或冒泡,但是进一步沿着树向上或向下的每个处理程序还是可以收到这些事件!这只能在过程式代码中完成,使用AddHandler的重载添加一个布尔型的参数handledEventsToo。
    例如:
            AddHandler(Window.MouseRightButtonDownEvent, new MouseButtonEventHandler(AboutDialog_MouseRightButtonDown), true);
    
    把true传递给第三个参数意味着:即使当你用鼠标右键单击一个ListBoxItem时,AboutDialog_MouseRightButtonDown也可收到事件了。
    在任何时候,都应该尽可能地避免处理已处理过的事件,因为事件应该是在第一时间被处理的。向一个事件的Preview版本添加一个处理程序是不错的替代方法。
    总之,终止管道传递或者冒泡仅仅是一种假象而已。更加准确的说法应该是,当一个路由事件标记为已处理时,管道传递和冒泡仍然会继续,但默认情况下,事件处理程序只会处理没有处理过的事件。

  • 使用指示笔事件
    指示笔是一种类似于笔的平板电脑(TabletPC)使用的设备,其默认的行为很像鼠标。换句话说,使用它可以触发一些事件,如MouseMove、MouseDown和MouseUp事件。这一行为对于指示笔至关重要,使它可以在任何程序中使用,而不仅仅局限于平板电脑。然而,如果你打算提供一种针对指示笔优化的体验,可以处理一些指示笔专用的事件,例如StylusMove、StylusDown和StylusUp。指示笔要比鼠标更有“技巧”,因为指示笔的有些事件是没有对应的鼠标事件的,如StylusInAirMove、StylusSystemGesture、StylusInRange和StylusOutOfRange。还有其他一些方式可以挖掘指示笔的功能,而不需要直接处理这些事件。

  • 处理单击鼠标中键的事件在哪里?
    如果你浏览一遍由UIElement或ContentElement提供的所有鼠标事件, 可以找到MouseLeftButtonDown、MouseLeftButtonUp、MouseRightButtonDown和MouseRightButtonUp事件(还有每个事件的管道Preview版本),但是有些鼠标上出现的附加按键该怎么办呢?
    这一信息可以通过更加通用的MouseDown和MouseUp事件获得(这两个事件也有对应的Preview事件)。传入这样的事件处理程序的参数包括一个MouseButton枚举值,它表示鼠标状态刚刚改变, 它们是Left 、Right、Middle 、XButton1 或XButton2, 还有一个对应的MouseButtonState枚举值,表示这个按钮是Pressed还是Released。

  • 所有的RoutedUICommand对象定义了一个Text属性,其中包含了命令的名称,适合显示在用户界面中。(该属性是RoutedUICommand和它的基类RoutedCommand唯一不同的地方。)例如,Help命令的Text属性是(不要感到惊讶)Help字符串。在这个Button上对Content做的硬编码可以用下面的代码替代:
    helpButton.Content = ApplicationCommands.Help.Text;
    Text字符串是由每个RoutedUICommand定义的,WPF会自动对Text作本地化,并把它转换为任何一种WPF支持的语言。这意味着, 如果一个按钮的Content属性被设置为ApplicationCommands.Help.Text,那么如果当前线程的UI文化是西班牙文(Spanish)而不是英文(English),它将自动显示“Ayuda”而不是“Help”。尽管在某些上下文中需要提供的是图像而不是文字(可能是在一个工具栏中),仍然可以在其他地方使用该本地化字符串,例如在ToolTip(工具栏提示)中。当然,你还是需要对你自己的字符串做本地化,这些字符串将在你的用户界面中显示。调整命令的Text属性可以减少你需要翻译的术语的数量。

  • 当把KeyBinding和MouseBinding对象添加到相关元素的InputBindings集合中时,就可以把自己的输入手势绑定到一个命令上。
    例如,如果要设定F2作为执行Help命令的键盘快捷方式,需要在AboutDialog构造函数中添加下面语句:
    InputBindings.Add(new KeyBinding(ApplicationCommands.Help, new KeyGesture(Key.F2)));
    然而,这样的话F1和F2都会执行Help命令。如果把F1绑定到一个特殊的NotACommand命令上,可以改变F1的默认行为,如下所示:
    InputBindings.Add(new KeyBinding(ApplicationCommands.NotACommand, new KeyGesture(Key.F1)));
    这两句语句可以用下面的XAML语句替代:
        <Window.InputBindings>
            <KeyBinding Command="Help" Key="F2"/>
            <KeyBinding Command="NotACommand" Key="F1"/>
        </Window.InputBindings>
    

  • 内建命令绑定
    <StackPanel xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      Orientation="Horizontal" Height="25">
      <Button Command="Cut" CommandTarget="{Binding ElementName=textBox}"
        Content="{Binding RelativeSource={RelativeSource Self}, Path=Command.Text}"/>
      <Button Command="Copy" CommandTarget="{Binding ElementName=textBox}"
        Content="{Binding RelativeSource={RelativeSource Self}, Path=Command.Text}"/>
      <Button Command="Paste" CommandTarget="{Binding ElementName=textBox}"
        Content="{Binding RelativeSource={RelativeSource Self}, Path=Command.Text}"/>
      <Button Command="Undo" CommandTarget="{Binding ElementName=textBox}"
        Content="{Binding RelativeSource={RelativeSource Self}, Path=Command.Text}"/>
      <Button Command="Redo" CommandTarget="{Binding ElementName=textBox}"
        Content="{Binding RelativeSource={RelativeSource Self}, Path=Command.Text}"/>
      <TextBox x:Name="textBox" Width="200"/>
    </StackPanel>Next
    
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值