WPF的重要新概念

逻辑树与可视树

逻辑树:WPF中,界面由一个对象树构建而成,这由于它具有层次化特征。

可视树:从逻辑树扩展,不是把每个元素当做一个节点黑盒,比如对于ListBox在逻辑树中为一不可分割节点,但在可视树概念中为多个对象(TextBox,Border等)复合而成。

使用System.Windows.LogicalTreeHelper和System.Windows.Media.VisualTreeHelper可方便的便利逻辑树和可视树。

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    x:Class="WPF_Test.MainWindow"
    Title="窗体" 
	SizeToContent="WidthAndHeight" 
	Background="OrangeRed">
    <StackPanel>
        <Label FontWeight="Bold" FontSize="20" Foreground="White">
            WPF Unleashed
        </Label>
        <Label>Publishing</Label>
        <Label>Publishing 2</Label>
        <ListBox>
            <ListBoxItem>List 1</ListBoxItem>
        </ListBox>
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
            <Button MinWidth="75" Margin="10">OK</Button>
        </StackPanel>
        <StatusBar>成功创造窗口</StatusBar>
    </StackPanel>
</Window>
namespace WPF_Test
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        //构造函数,程序入口点
        public MainWindow()
        {
            InitializeComponent();
            GetLogicalTree(0, this);
        }

        #region 事件处理

        //布局完成
        protected override void OnContentRendered(EventArgs e)
        {
            base.OnContentRendered(e);
            //可视树在布局完成后才会有节点
            GetVisualTree(0, this);
        }

        #endregion

        #region 方法

        private void GetLogicalTree(int depth, object obj)
        {
            Debug.WriteLine(new string(' ', depth) + obj);

            if (!(obj is DependencyObject))
            {
                return;
            }

            foreach (object child in LogicalTreeHelper.GetChildren(obj as DependencyObject))
            {
                GetLogicalTree(depth + 1, child);
            }
        }

        private void GetVisualTree(int depth, DependencyObject obj)
        {
            Debug.WriteLine(new string(' ',depth) + obj);

            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
            {
                GetVisualTree(depth + 1, VisualTreeHelper.GetChild(obj, i));
            }
        }

        #endregion
    }
}

 

依赖属性

WPF引入新属性类型,用来实现样式化,自动数据绑定,动画等。在任何时候都是依赖多个提供程序来判断它的值。其最大特征是其内建传递变更通知的能力。

1.依赖属性的实现

public partial class MainWindow : Window
{
    //定义一依赖属性(必须public static)
    //名称后缀为Property
    public static DependencyProperty IsDefaultProperty;
    //构造函数,程序入口点
    public MainWindow()
    {
        //注册依赖属性名,属性类型,所有者类型,属性元数据(默认值,值改变后的回调函数)
        MainWindow.IsDefaultProperty = DependencyProperty.Register("IsDefault",
            typeof(bool), typeof(MainWindow),
            new FrameworkPropertyMetadata(false, OnIsDefaultChanged));
    }

    //.Net属性包装器(可选)
    //GetValue(),SetValue()来至控件底层基类System.Windows.DependencyObject,依赖属性的类必须继承
    public bool IsDefault
    {
        get { return (bool)GetValue(MainWindow.IsDefaultProperty); }
        set { SetValue(MainWindow.IsDefaultProperty, value); }
    }

    //依赖属性值改变,回调处理方法
    private static void OnIsDefaultChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
    {
        //改变主窗体的背景颜色
        MainWindow win = obj as MainWindow;
        win.Background = Brushes.Purple;
    }

    //点击按钮改变依赖属性值
    private void Button_Click(object sender, RoutedEventArgs e)
    {
        IsDefault = true;
    }
}

2.变更通知

无论何时,只要依赖属性值变了,WPF就会自动根据属性元数据(metadata)触发一系列动作。

<Button MinWidth="75" Margin="10" Click="Button_Click">OK
    <Button.Style>
        <Style TargetType="{x:Type Button}">
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Foreground" Value="Blue"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Button.Style>
</Button>

注:人为原因,按钮Trigger对象仅在Style对象里使用
3.属性值继续

非传统面向对象的类继承,是指属性值由父节点向下沿着其子节点传递。
注:1.并不是每个依赖属性都参与属性值继承

        2.有其他优先级更高的来源来设置这些值

4.对多个提供程序的支持

5.附加属性

依赖属性的特殊形式,可被有效添加到任何对象中

<StackPanel TextElement.FontSize="20">
    <Button MinWidth="75" Margin="10">OK</Button>
</StackPanel>


路由事件

路由事件触发后,可以向上或向下遍历可视树和逻辑树,以简单而且持久的方式在每个元素上触发。

1.路由事件的实现

public partial class MainWindow : Window
{
    //定义路由事件
    //名称后缀Event
    public static RoutedEvent ClickEvent;

    public MainWindow()
    {
        //注册路由事件
        MainWindow.ClickEvent = EventManager.RegisterRoutedEvent("Click", 
            RoutingStrategy.Bubble, 
            typeof(RoutedEventHandler), 
            typeof(MainWindow));

        //添加一个事件订阅
        Click += MainWindow_Click;
    }

    //.Net路由事件包装器(可选)
    public event RoutedEventHandler Click
    {
        add { AddHandler(MainWindow.ClickEvent, value); }
        remove { RemoveHandler(MainWindow.ClickEvent, value); }
    }

    //重写基类点击鼠标左键处理方法
    protected override void  OnMouseLeftButtonDown(MouseButtonEventArgs e)
    {
        //触发路由事件
        RaiseEvent(new RoutedEventArgs(MainWindow.ClickEvent, this));
    }

    //路由事件处理方法
    private void MainWindow_Click(object sender, RoutedEventArgs e)
    {
        MainWindow win = sender as MainWindow;
        win.Background = Brushes.BurlyWood;
    }
}

2.路由策略和事件处理程序

路右策略即事件触发遍历整棵元素树的方式:

Tunneling(管道传递):先在根元素触发,由根元素向下沿树传递,直到到达源元素为止。

Bubbling(冒泡):先在源元素触发,再沿着树向上传递,直到到达根元素为止。

Direct(直接):仅在源元素上触发。

3.路由事件实践

管道事件:Preview前缀,在它们的配对冒泡事件发生前,这些事件会立刻触发。

在事件处理程序中设置RoutedEventArgs参数的Handled属性为true,可以终止管道传递或冒泡。

4.附加事件

每个路由事件都可以当做附加事件使用

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    x:Class="WPF_Test.MainWindow" 
    Title="窗体" 
    SizeToContent="WidthAndHeight" 
    Background="OrangeRed"
    ButtonBase.Click="MainWindow_Click">
    <Button>dd</Button>
</Window>

 

命令

WPF提供内建命令支持
1.内建命令

命令是任何实现System.Windows.Input.ICommand接口的对象。

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    x:Class="WPF_Test.MainWindow">
    <!-- 指定一内建命令,点击F1也能触发 -->
    <Window.CommandBindings>
        <CommandBinding Command="Help" CanExecute=" HelpCanExecute" 
        Executed="HelpExecute" />
    </Window.CommandBindings>
</Window>
#region 内建命令

protected void HelpCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
    e.CanExecute = true;
}

protected void HelpExecute(object sender, ExecutedRoutedEventArgs e)
{
    MainWindow win = sender as MainWindow;
    win.Background = Brushes.BurlyWood;
}

#endregion

2.使用输入手势执行命令

以上默认Help命名是绑定F1,入需指定,可以:

<Window.InputBindings>
        <KeyBinding Command="Help" Key="F2"/>
</Window.InputBindings>

F1,F2都将响应Help命令

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值