zoukankan      html  css  js  c++  java
  • WPF进阶技巧和实战05-样式与行为

    系列文章链接

    样式(style)是组织和重用格式化选项的重要工具。创建一系列封装某些细节的样式,然后通过属性来应用样式。

    行为(behavior)是一款重用用户界面代码更有挑战性的工具。基本思想是:使用行为封装一些通用的UI功能。如果具有适当的行为,可使用一两行XAML标记将其附加到任何元素。

    样式基础

    样式就是可应用于元素的属性值集合。样式支持触发器,当属性发生变化时,可通过触发器改变控件的样式。

    样式有5个重要属性:

    属性 说明
    Setters 设置属性值,自动关联事件处理程序的Setter对象或者EventSetter对象的集合
    Triggers 继承自TriggerBase类,并能自动改变样式设置的对象集合。例如,当另一个属性改变时,或者当发生某个事件时,可以修改样式
    Resources 希望用于样式的资源集合。例如,可能需要使用一个对象设置多个属性。这时,更高效 的做法是作为资源创建对象,然后再Setter对象中使用该资源(而不是使用嵌套的标签为每一个Setter对象的一部分创建对象)
    BasedOn 通过该属性可创建继承自(并且可以选择地进行重写)其他样式设置的更具体形式
    TargetType 该属性标识应用样式的元素类型。通过该属性可创建只影响特定类型元素的设置器,还可以创建能够为恰当的元素类型自动起作用的设置器
    <Style x:Key="TextBlockBaseStyle" TargetType="{x:Type TextBlock}">
        <Setter Property="TextWrapping" Value="NoWrap" />
        <Setter Property="TextTrimming" Value="None" />
        <Setter Property="VerticalAlignment" Value="Center" />
        <Setter Property="HorizontalAlignment" Value="Center" />
        <Setter Property="Width" Value="Auto" />
        <Setter Property="Height" Value="Auto" />
    </Style>
    

    触发器

    使用触发器,可以自动完成简单的样式改变,例如,当属性发生改变时进行相应,并自动调整样式。触发器通过Style.Triggers集合链接到样式。每个样式都可以有任意多个触发器,而且每个触发器都是TriggerBse的派生类实例。

    名称 说明
    Trigger 最简单的触发器,可以监测依赖项属性的变化,然后使用设置器改变样式
    MutiTrigger 和Trigger类似,但是触发器联合了多个条件。只有满足所有条件,才会启动触发器
    DataTrigger 这种触发器使用数据绑定,与Trigger类似,只不过监测是任意绑定数据的变化
    MultiDataTrigger 联合多个数据触发器
    EventTrigger 最复杂的触发器,当事件发生时,这种触发器应用动画

    简单触发器

    每个简单的触发器都指定了正在监视的属性,以及正在等待的属性值。触发器的优点是不需要为翻转他们而编写任何逻辑。只要停止触发器(条件不满足时),元素就会恢复到之前的属性值。

    <Style.Triggers>
        <Trigger Property="IsMouseOver" Value="True">
            <Setter Property="Opacity" Value=".9" />
        </Trigger>
        <Trigger Property="IsPressed" Value="True">
            <Setter Property="Opacity" Value=".6" />
        </Trigger>
        <Trigger Property="IsEnabled" Value="False">
            <Setter Property="Opacity" Value="0.4" />
        </Trigger>
    </Style.Triggers>
    

    触发器的顺序决定了哪个触发器最终生效,最后的触发器会生效。

    如果希望创建只有当几个条件都成立时才激活的触发器,就可以使用MutiTrigger。这种触发器提供了一个Conditions集合,可通过该集合定一系列触发条件,这些条件不分先后顺序,只有全部满足时,触发器才会工作。

    事件触发器

    普通触发器等待属性发生变化,而事件触发器等待特定的事件被触发。事件触发器要求用户提供一系列修改控件的动作,这些动作通常被用作动画。

    行为

    基本思想:创建封装了一些通用用户界面功能的行为。这一功能可以是基本功能(如启动故事板或导航到超链接),也可以是复杂功能(如处理多点触摸交互,或构建使用实时物理引擎的碰撞模型)。一旦构建功能,就可将他们添加到任意应用程序的另一个控件中,具体方法是将该控件链接到适当的行为并设置行为的属性。

    using Microsoft.Xaml.Behaviors;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media;
    namespace Course04
    {
        public class DragInCanvasBehavior : Behavior<UIElement>
        {
            protected override void OnAttached()
            {
                base.OnAttached(); 
                
                this.AssociatedObject.MouseLeftButtonDown += AssociatedObject_MouseLeftButtonDown;
                this.AssociatedObject.MouseMove += AssociatedObject_MouseMove;
                this.AssociatedObject.MouseLeftButtonUp += AssociatedObject_MouseLeftButtonUp;
            }
            protected override void OnDetaching()
            {
                base.OnDetaching();
                this.AssociatedObject.MouseLeftButtonDown -= AssociatedObject_MouseLeftButtonDown;
                this.AssociatedObject.MouseMove -= AssociatedObject_MouseMove;
                this.AssociatedObject.MouseLeftButtonUp -= AssociatedObject_MouseLeftButtonUp;
            }
    
            Canvas canvas = null;
            bool isDragging = false;
            Point mouseOffset;
            private void AssociatedObject_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
            {
                if(isDragging)
                {
                    this.AssociatedObject.ReleaseMouseCapture();
                    isDragging = false;
                }
            }
            private void AssociatedObject_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
            {
                if(isDragging)
                {
                    Point point = e.GetPosition(canvas);
                    this.AssociatedObject.SetValue(Canvas.LeftProperty, point.X - mouseOffset.X);
                    this.AssociatedObject.SetValue(Canvas.TopProperty, point.Y - mouseOffset.Y);
                }
            }
            private void AssociatedObject_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
            {
                if(canvas == null)
                {
                    canvas = (Canvas)VisualTreeHelper.GetParent(this.AssociatedObject); 
                }
                isDragging = true;
                mouseOffset = e.GetPosition(this.AssociatedObject);
                this.AssociatedObject.CaptureMouse();
            }
            
        }
    }
    

    XAML代码:

    <Window
        x:Class="Course04.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Course04"
        Title="MainWindow"
        Width="800"
        Height="450"
        mc:Ignorable="d">
        <Grid>
            <MediaElement LoadedBehavior="Play" Source="Normal.wav" Visibility="Collapsed" />
            <Canvas>
                <Rectangle Canvas.Left="60" Canvas.Top="20" Width="40" Height="50" Fill="Red" />
                <Ellipse Canvas.Left="80" Canvas.Top="100" Width="80" Height="50" Fill="Green">
                    <b:Interaction.Behaviors>
                        <local:DragInCanvasBehavior />
                    </b:Interaction.Behaviors>
                </Ellipse>
                <Rectangle Canvas.Left="70" Canvas.Top="200" Width="40" Height="50" Fill="Yellow" />
            </Canvas>
        </Grid>
    </Window>
    
  • 相关阅读:
    [EffectiveC++]item22:Declare data members private
    垃圾人定律
    [EffectiveC++]item17:以独立语句将newed对象置入智能指针
    [EffectiveC++]item15:Provide access to raw resources in resource-managing class
    C++ 中operator用法:隐式类型转换
    [EffectiveC++]item13:Use objects to manage resources(RAII)
    为什么拷贝构造函数的参数必须是引用?
    SPF邮件服务器
    raspberry
    bash
  • 原文地址:https://www.cnblogs.com/vigorous/p/15075511.html
Copyright © 2011-2022 走看看