WPF实现Interaction框架的Behavior扩展

在WPF 4.0中,引入了一个比较实用的库——Interactions,这个库主要是通过附加属性来对UI控件注入一些新的功能,除了内置了一系列比较好用的功能外,还提供了比较良好的扩展接口。本文这里简单的介绍一下Behavior这个扩展。

顾名思义,Behavior可以赋予控件新的行为能力,例如,我们可以通过MouseDragElementBehavior给控件附加上支持拖放的能力。使用方式如下:

  • 添加Interactions库的引用。主要添加如下两个DLL:Microsoft.Expression.Interactions.dll和System.Windows.Interactivity.dll。
  • 添加如下名字空间

    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"

  • 在控件中添加MouseDragElementBehavior
    <Image Source="2.jpg" >
        <i:Interaction.Behaviors>
            <ei:MouseDragElementBehavior/>
        </i:Interaction.Behaviors>
    </Image>

这三步中前面几步都是添加Interactions库的支持,对于后面介绍的Trigger和Action也是一样的,只有<ei:MouseDragElementBehavior/>一句才是和Behavior相关的。实际上,我们可以通过在Blend里直接将MouseDragElementBehavior拖放到控件上简化这一过程。加上MouseDragElementBehavior后,我们的控件就支持鼠标拖拽移动了,非常给力。

实际上,系统还提供了一系列非常好用的Behavior,后面我再单独写文章来介绍它。

编写自己的Behavior

除了系统自己提供的Behavior外,我们也可以通过自己编写Behavior来实现自定义行为,一个简单的示例如下:

    class SkewBehavior : Behavior<UIElement>
    {
        SkewTransform _transForm;

        protected override void OnAttached()
        {
            base.OnAttached();

            _transForm = new SkewTransform();

            AssociatedObject.RenderTransform = _transForm;
            AssociatedObject.RenderTransformOrigin = new Point(0.5, 0.5);
            _transForm.AngleX = 30;
        }

        protected override void OnDetaching()
        {
            _transForm.AngleX = 0;
            base.OnDetaching();
        }
    }

上面的代码同样实现了一个将控件水平方向倾斜30度的Behavior(实现得比较简单,并不完善),大体上关键的地方有如下三个:

  • 通过AssociatedObject属性获取附加的对象。
  • 通过重载OnAttached函数进行Behavior附加上时的初始化操作
  • 通过重载OnDetaching函数进行移除Behavior时候的析构操作

虽然我们也可以直接通过附加属性实现这样的功能,但Interactions框架无疑规范并简化了这一行为。

最后,附上一个比较常用的鼠标拖放的Behavior,和内置的MouseDragElementBehavior不同的是,它产生鼠标事件,用于实现一些自定义的拖放操作:

    class DragDropBehavior : Behavior<UIElement>
    {
        public event EventHandler<DragDeltaEventArgs> DragDelta;
        public event EventHandler<EventArgs> Drop;

        IInputElement _parent;

        protected override void OnAttached()
        {
            base.OnAttached();

            _parent = LogicalTreeHelper.GetParent(AssociatedObject) as IInputElement;

            if (_parent == null)
                return;

            AssociatedObject.MouseLeftButtonDown += onMouseDown;
            AssociatedObject.MouseMove += onMouseMove;

            AssociatedObject.MouseLeftButtonUp += onMouseUp;
            AssociatedObject.MouseEnter += onDragEnter;
        }

        protected override void OnDetaching()
        {
            AssociatedObject.MouseLeftButtonDown -= onMouseDown;
            AssociatedObject.MouseMove -= onMouseMove;

            AssociatedObject.MouseLeftButtonUp -= onMouseUp;
            AssociatedObject.MouseEnter -= onDragEnter;

            base.OnDetaching();
        }

        Point? start;
        private void onMouseDown(object sender, MouseButtonEventArgs e)
        {
            start = Mouse.GetPosition(_parent);
        }

        private void onMouseMove(object sender, MouseEventArgs e)
        {
            if (!start.HasValue)
                return;

            var p = Mouse.GetPosition(_parent);
            var offset = p - start.Value;

            start = p;

            DragDelta?.Invoke(AssociatedObject, new DragDeltaEventArgs(offset.X, offset.Y));
        }

        private void onMouseUp(object sender, MouseButtonEventArgs e)
        {
            tryEndDrag();
        }

        private void onDragEnter(object sender, MouseEventArgs e)
        {
            tryEndDrag();
        }

        void tryEndDrag()
        {
            if (Mouse.LeftButton != MouseButtonState.Released)
                return;

            start = null;

            Drop?.Invoke(AssociatedObject, EventArgs.Empty);
        }
    }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 在WPF中使用多线程更新UI

    有经验的程序员们都知道:不能在UI线程上进行耗时操作,那样会造成界面卡顿,如下就是一个简单的示例: public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); this.Dispatcher.Invoke(new Action(()=> { })); this.Loaded += MainWindow_Loaded; } private void MainWindow_Loaded

  • WPF使用FontAwesome字体图标

    在WPF程序中,一般接触到的矢量图标资源有XAML.SVG.字体这三种格式.XAML是标准格式就不说了,SVG并不是直接支持的,不过微软提供了Expression Design可以非常方便我们将其转换为XAML格式的资源.而对于字体,虽然WPF是直接支持的,但由于字体图标其特殊性,要将其显示为图标还是需要费点劲的.本文这里就以Font-Awesome为例,介绍一下如何在WPF中使用字体图标. 首先添加一个样式,为了使用方便,建议直接做为全局样式: <Style x:Key="FontAwe

  • WPF中使用CallerMemberName简化InotifyPropertyChanged的实现

    在WPF中,当我们要使用MVVM的方式绑定一个普通对象的属性时,界面上往往需要获取到属性变更的通知, class NotifyObject : INotifyPropertyChanged { private int number; public int Number { get { return number; } set { number = value; OnPropertyChanged("Number"); } } private string text; public st

  • 解决WPF附加属性的Set函数不调用的问题

    今天写程序的时候用到了附加属性,我是用VS内置的propa的代码段来实现的,代码如下: class Attach { public static bool GetIsEnabled(DependencyObject obj) { return (bool)obj.GetValue(IsEnabledProperty); } public static void SetIsEnabled(DependencyObject obj, bool value) { obj.SetValue(IsEnab

  • 在WPF中合并两个ObservableCollection集合

    WPF中的ObservableCollection是一个非常常用的集合对象,我们可以通过将它绑定到ListBox之类的集合控件上时,当集合发生变更时,会同步更新到界面上.但是,有的时候我们需要合并两个集合,将他们的拼接后显示在界面上,此时该何如做呢? 乍一看来,这是个非常简单的事情,.Net的BCL本身就提供了IEnumerate集合连接函数——Concat,可以通过它轻松连接两个集合.但当你使用它连接集合并果呈现到界面上时,就会发现一个问题——虽然它可以将当前结果拼接起来显示,但却不会同步显示

  • C#开发WPF程序中的弱事件模式

    在C#中,得益于强大的GC机制,使得我们开发程序变得非常简单,很多时候我们只需要管使用,而并不需要关心什么时候释放资源.但是,GC有的时并不是按照我们所期望的方式工作. 例如,我想实现一个在窗口的标题栏中实时显示当前的时间,一个比较常规的做法如下: var timer = new DispatcherTimer() { Interval = TimeSpan.FromSeconds(1) }; timer.Tick += (_s, _e) => this.Title = DateTime.Now

  • 在WPF中实现平滑滚动的方法详解

    WPF实现滚动条还是比较方便的,只要在控件外围加上ScrollViewer即可,但美中不足的是:滚动的时候没有动画效果.在滚动的时候添加过渡动画能给我们的软件增色不少,例如Office 2013的滚动的时候支持动画看起来就舒服多了. 之前倒是研究过如何实现这个平滑滚动,不过网上的方案大部分大多数如下: 通过VisualTree找到ScrollViewer 在ScrollChanged事件中添加动画 这种方案效果并不好,以为我们的滚动很多时候都是一口气滚动好几格滚轮的,这个时候上一个动画还没有结束

  • WPF实现Interaction框架的Behavior扩展

    在WPF 4.0中,引入了一个比较实用的库——Interactions,这个库主要是通过附加属性来对UI控件注入一些新的功能,除了内置了一系列比较好用的功能外,还提供了比较良好的扩展接口.本文这里简单的介绍一下Behavior这个扩展. 顾名思义,Behavior可以赋予控件新的行为能力,例如,我们可以通过MouseDragElementBehavior给控件附加上支持拖放的能力.使用方式如下: 添加Interactions库的引用.主要添加如下两个DLL:Microsoft.Expressio

  • ThinkPHP框架设计及扩展详解

    ThinkPHP框架是国内知名度很高应用很广泛的php框架,我们从一些简单的开发示例中来深入了解一下这个框架给我们带来的开发便捷性,以及游刃有余的扩展设计.同时也从源码分析的角度看看框架的一些不足,尽量做全面客观的评价.这里假设大家已经使用过ThinkPHP框架,基本使用方法请参考官方文档. 一.框架分层及url路由 框架的安装非常简单,下载后放入web服务器的目录即可,但是建议大家不要用默认的入口文件位置,而是放入单独的目录,便于保护代码和数据.例如我的入口文件和web服务器配置目录在web目

  • YII2框架中behavior行为的理解与使用方法示例

    本文实例讲述了YII2框架中behavior行为的理解与使用方法.分享给大家供大家参考,具体如下: YII2中的行为说白了就是对组件功能的扩展,在不改变继承关系的条件下. 行为附加到组件后,行为将注入自已的方法和属性到组件,可以像组件访问自定义的方法和属性一样访问行为. 注意行为是对功能的扩展,不要乱用行为,比如有一个动物类和一个人类,他们各自有自已的名称,身高,体重,这些是属性. 他们都会跑,这个时候我们就可以抽象出来做成一个跑的行为,根据不同需求来扩展他们. 这里我们有两个控制器一个Good

  • Java基础之MapReduce框架总结与扩展知识点

    一.MapTask工作机制 MapTask就是Map阶段的job,它的数量由切片决定 二.MapTask工作流程: 1.Read阶段:读取文件,此时进行对文件数据进行切片(InputFormat进行切片),通过切片,从而确定MapTask的数量,切片中包含数据和key(偏移量) 2.Map阶段:这个阶段是针对数据进行map方法的计算操作,通过该方法,可以对切片中的key和value进行处理 3.Collect收集阶段:在用户编写map()函数中,当数据处理完成后,一般会调用OutputColle

  • WPF引用MVVM框架与使用方法

    1.NuGet引用MVVM框架包 引入该框架包之后, 默认会在目录下创建ViewModel层的示例代码 2.第二步, 通过在MainViewModel中创建一些业务代码, 将其与MainWindow.xaml 通过上下文的方式关联起来, 而MainWindow则是通过Binding的写法 引用业务逻辑的部分. 在MainViewModel中, 添加同一个班级名称, 与学生列表, 分别用于显示在文本 和列表上展示, Command则用于绑定DataGrid的双击命令上, 通过双击, 展示点击行的学

  • Nlog日志框架集成Seq扩展包

    什么是Seq? 正如我们使用不同的日志框架来为我们的应用程序收集各类日志信息, 这些信息可以有效的帮助我们快速诊断应用程序中发生的各类问题, 尽管如此,对于常见的日志框架而言, 它们往往只是解决了日志功能快速集成以及如何配置输出保存等功能. 对于那些不间断运行的应用程序而言, 日志的存储和维护工作会变得异常麻烦, 如果想灵活的在不同时间段去查找日志, 根据不同的日志类型快速的定位问题, 这会变得非常困难,所以为了解决这些问题, Seq就登场了.Seq提供了收集应用程序日志.搜索过滤.警告以及图表

  • yii框架分类树扩展示例

    提供两种方式的分类树格式,表格和下拉框形式的树形结构可以自定义表格和下拉框的样式,自定义以哪一列的参数为格式化数据,自定义层级关系参数,自定义表格列名称,也可以设置时间的格式化. 调用方式 表格方式: 复制代码 代码如下: <?php $this->widget('ext.tree.widgets.TreeWidget',array(        'dataProvider'  => $dataProvider,           // 传递数据        'pid'      

  • WPF中的导航框架概述

    有的时候,我们需要一个支持页面跳转的UI,例如文件浏览器,开始向导等.对于这样的界面,简单的可以使用ContentControl + ContentTemplateSelector的方式来实现,但是有的时候我们会需要一些更加高级的跳转功能,如前进,回退等.这个时候,用这个方式就稍微有点力不从心了,此时,我们可以使用WPF的导航框架帮助我们快速实现这一功能. WPF 的Page框架主要包括两个部分,容器和页面, 下面就以一个简单的例子来介绍WPF的Page框架,首先我们创建第一个页面: <Page

  • c# WPF中System.Windows.Interactivity的使用

    背景 在我们进行WPF开发应用程序的时候不可避免的要使用到事件,很多时候没有严格按照MVVM模式进行开发的时候习惯直接在xaml中定义事件,然后再在对应的.cs文件中直接写事件的处理过程,这种处理方式写起来非常简单而且不用过多地处理考虑代码之间是否符合规范,但是我们在写代码的时候如果完全按照WPF规范的MVVM模式进行开发的时候就应该将相应的事件处理写在ViewModel层,这样整个代码才更加符合规范而且层次也更加清楚,更加符合MVVM规范. 常规用法 1 引入命名空间 通过在代码中引入Syst

  • 百万行WPF项目代码重构记录分析

    目录 一 产品型号太多产生非常多重复性工作 二 配置零散,没有统一的管理机制,不利于打包 三 UI和业务逻辑混杂 四 开发人员的层次不一 五 处理大量的图片 内存和CPU占用过大 此前带领小组成员主导过一个百万行代码上位机项目的重构工作,分析项目中存在的问题做了些针对性的优化,整个重构工作持续了一年半之久. 主要针对以下问题: 一 产品型号太多产生非常多重复性工作 产品型号太多导致代码工程的分支太多,维护时会产生非常多的重复性的工作. 这是一个历史遗留问题,公司成立之初的开发人员在开发时没有考虑

随机推荐