《WPF揭秘》学习随笔 01

本文介绍了WPF编程中的实用技巧,包括XAML中实现按钮样式变化、遍历逻辑和可视树、处理鼠标和指示笔事件、命令绑定等。通过这些技巧,开发者能够更好地理解和掌握WPF的应用开发。
  • 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
    
    
Windows Presentation Foundation (WPF) 是.NET Framework 3.0 的关键组件,是支持下一代视窗应用程序表现层编程的平台,也是微软新发布的Vista操作系统的三大核心开发库之一,主要负责图形显示。本书是针对那些对用户界面开发感兴趣的软件开发人员编写的,易于理解,适合那些.NET的新手,并有助于理解像Microsoft Expression Blend这样产品的精髓。   本书适合各层次Web开发人员阅读。 第一部分 背景 第1章 为什么创造WPF    1.1 回顾过去    1.2 步入WPF    1.3 作为.NET Framework的组成部分     1.3.1 为托管代码而设计     1.3.2 强调声明式描述    1.4 小结   第2章 XAML揭秘    2.1 XAML定义    2.2 元素和特性    2.3 命名空间    2.4 属性元素    2.5 类型转换器    2.6 标记扩展    2.7 对象元素的子元素     2.7.1 内容属性     2.7.2 集合项     2.7.3 更多类型转换    2.8 编译:将XAML与过程式代码混合使用     2.8.1 在运行时加载和解析XAML     2.8.2 编译XAML     2.8.3 XAML关键字    2.9 小结     2.9.1 抱怨1:XML太过冗长不便于输入     2.9.2 抱怨2:基于XML的系统性能差   第3章 WPF的重要新概念    3.1 逻辑树与可视树    3.2 依赖属性     3.2.1 依赖属性的实现     3.2.2 变更通知     3.2.3 属性值继承     3.2.4 对多个提供程序的支持     3.2.5 附加属性    3.3 路由事件     3.3.1 路由事件的实现     3.3.2 路由策略和事件处理程序     3.3.3 路由事件实践     3.3.4 附加事件    3.4 命令     3.4.1 内建命令     3.4.2 使用输入手势执行命令     3.4.3 带有内建命令绑定的控件    3.5 漫游类层次    3.6 小结  第二部分 构建WPF应用程序  第4章 WPF控件   第5章 尺寸缩放、定位与变换元素   第6章 使用面板做布局   第7章 构建并部署应用程序  第三部分 为专业开发人员设计的功能  第8章 资源   第9章 数据绑定   第10章 样式、模板、皮肤和主题 233 第四部分 通过富媒体使程序领先于时代  第11章 2D图形   第12章 3D图形   第13章 动画   第14章 音频、视频、语音和文档  第五部分 高级主题  第15章 与Win32、Windows Form以及ActiveX之间的互用性   第16章 用户控件和自定义控件   第17章 使用自定义面板做布局  第六部分 附录 附录 有用的工具 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值