首页 > 其他分享 >WPF事件

WPF事件

时间:2024-08-16 21:27:56浏览次数:13  
标签:sender void AssociatedObject private start 事件 WPF border

鼠标输入事件

必须继承 FrameworkElement:UIElement

鼠标事件:

MouseEnter

MouseLeave

MouseDown

MouseUp

MouseMove

MouseLeftButtonDown

MouseLeftButtonUp

MouseRightButtonDown

MouseRightButtonUp

MouseDoubleClick

Click:事件:特殊

<Button Content="Mouse Event" MouseLeftButtonDown="Button_MouseLeftButtonDown" />

所有对象都能写出MouseLeftButtonDown这个事件

由于 Button 中,重写了MouseLeftButtonDown事件,先处理的是Click事件,处理完之后事件完毕

所以不会处理Button_MouseLeftButtonDown

Button上的MouseLeftButtonDown无法直接触发,但是可以触发PreviewMouseLeftButtonDown事件

捕获鼠标:
// 第一种 把对象绑定到光标上 两种处理
Mouse.Capture(border);
// 第二种 强制捕捉鼠标
//this.border.CaptureMouse();
========================================
// 释放控件鼠标强制捕捉
Mouse.Capture(null);
//this.border.ReleaseMouseCapture();

键盘输入事件

KeyDown

KeyUp

TextInput

TextChanged

拖拽事件

Drop

DragLeave

DragOver

DragEnter

触控事件与笔势 (Stylus开头的事件)

如果在触控设备中,鼠标事件时灵时不灵的时候,换Touch事件处理

Touch PreviewTouch Win7 Surface

多点触控(Manipulation开头的事件),必须打开IsManipulationEnabled="True“

自定义事件

自定义普通事件

C#代码定义:

using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;

namespace XH.EventLesson
{
    /// <summary>
    /// CustomEventWindow.xaml 的交互逻辑
    /// </summary>
    public partial class CustomEventWindow : Window
    {
        public CustomEventWindow()
        {
            InitializeComponent();

            Test test = new Test();
            test.CustomEvent += Test_CustomEvent;
            test.CustomEvent -= Test_CustomEvent;
            test.CustomStringEvent += Test_CustomStringEvent;
            test.CustomStringEvent -= Test_CustomStringEvent;
        }


        private void Test_CustomStringEvent(object? sender, string e)
        {
            throw new NotImplementedException();
        }
        private void Test_CustomEvent(object? sender, MyEventArags e)
        {
            string value = e.Value;
            throw new NotImplementedException();
        }

    }
    // 普通事件
    class Test
    {
        // Framework 4.0 及以下框架下 可以使用
        public event EventHandler<MyEventArags> CustomEvent;

        // 4.5 及以上可以已使用以下方式
        public event EventHandler<string> CustomStringEvent;

        public Test()
        {
            CustomEvent?.Invoke(this, new MyEventArags() { Value = "Hello" });
            CustomStringEvent?.Invoke(this, "Hello");
        }
    }

    class MyEventArags : EventArgs
    {
        public string Value { get; set; }
    }
}
自定义路由事件

C#代码定义:

using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;

namespace XH.EventLesson
{
    /// <summary>
    /// CustomEventWindow.xaml 的交互逻辑
    /// </summary>
    public partial class CustomEventWindow : Window
    {
        public CustomEventWindow()
        {
            InitializeComponent();
        }
        private void ChildClass_Tap(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine("================ChildClass_Tap================");
        }
        private void ParentClass_Tap(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine("================ParentClass_Tap================");
        }

        private void ParentClass_PreviewTap(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine("================ParentClass_PreviewTap================");
        }

        private void ChildClass_PreviewTap(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine("================ChildClass_PreviewTap================");
        }

        private void Grid_PreviewTap(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine("================Grid_PreviewTap================");
        }

        private void Grid_Tap(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine("================Grid_Tap================");
        }
    }
    // 用于路由事件

    public class BaseClass : ContentControl
    {
        // 路由事件的声明与注册(冒泡事件)
        protected static readonly RoutedEvent TapEvent =
            EventManager.RegisterRoutedEvent(
                "Tap",
                RoutingStrategy.Bubble,
                typeof(RoutedEventHandler),
                typeof(BaseClass));

        // 封装
        public event RoutedEventHandler Tap
        {
            add => AddHandler(TapEvent, value);
            remove => RemoveHandler(TapEvent, value);
        }

        // 封装
        public event RoutedEventHandler PreviewTap
        {
            add => AddHandler(PreviewTapEvent, value);
            remove => RemoveHandler(PreviewTapEvent, value);
        }
        // 路由事件的声明与注册(隧道事件)
        protected static readonly RoutedEvent PreviewTapEvent =
            EventManager.RegisterRoutedEvent(
                "PreviewTap",
                RoutingStrategy.Tunnel,
                typeof(RoutedEventHandler),
                typeof(BaseClass));

    }

    public class ParentClass : BaseClass
    {
         
    }

    public class ChildClass : BaseClass
    {
        public ChildClass()
        {
            // 场景 类里数据执行到某个时机的时候 触发上面的路由事件
            Task.Run(async () =>
            {
                await Task.Delay(2000);

                // 触发路由事件
                this.Dispatcher.Invoke(() =>
                {
                    // 冒泡:从里到外,隧道:从外到里
                    // 先Child 在 Parent
                    this.RaiseEvent(new RoutedEventArgs(TapEvent, this));
                    // 先Parent 在 Child
                    this.RaiseEvent(new RoutedEventArgs(PreviewTapEvent, this));
                });
            });
        }

    }
}

XAML代码使用:

<Window x:Class="XH.EventLesson.CustomEventWindow"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  xmlns:local="clr-namespace:XH.EventLesson"
  mc:Ignorable="d"
  Title="CustomEventWindow" Height="450" Width="800">
  <Grid local:BaseClass.PreviewTap="Grid_PreviewTap" local:BaseClass.Tap="Grid_Tap">
    <local:ParentClass Tap="ParentClass_Tap" PreviewTap="ParentClass_PreviewTap">
      <local:ChildClass Tap="ChildClass_Tap" PreviewTap="ChildClass_PreviewTap" />
    </local:ParentClass>
  </Grid>
</Window>

使用演示:打印log

总结:冒泡:从里到外,隧道:从外到里

路由事件

逻辑树与视觉树

冒泡与隧道

MouseLeftButtonDown

PreviewMouseLeftButtonDown

路由事件的拦截

 private void Border_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
 {
     // 禁止路由事件传递
     e.Handled = true;
 }

注意:带有Preview的事件是隧道事件,不带的是路由事件。

路由拦截后的逻辑执行

每次拦截之后,就先执行当前的路由事件,不会触发冒泡事件

键盘输入事件

有个特别注意:TextInput

<TextBox TextInput="TextBox_TextInput" />

TextBox中不处理TextInput事件,如果想要处理值输入事件可以使用PreviewTextInput,或者用TextChanged代替。

拖拽事件

事件:

DragEnter:拖拽进入当前对象

DragLeave:拖拽离开当前对象

DragOver:拖拽在当前对象上移动(和MouseOver差不多)

Drop:拖过来的鼠标松开的那一刻触发

AllowDrop:允许接受拖拽

案例:

XAML代码:

<Window x:Class="XH.EventLesson.DragDropEventWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:XH.EventLesson"
        mc:Ignorable="d"
        Title="DragDropEventWindow" Height="450" Width="800">
    <Grid>
        <!--DragEnter:拖拽进入当前对象
            Drop:拖过来的鼠标松开的那一刻触发-->
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="200"/>
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <StackPanel>
            <Border Background="Red" Height="30" Margin="10" 
                    MouseLeftButtonDown="Border_MouseLeftButtonDown"/>
            <Border Background="Orange" Height="30" Margin="10"
                    MouseLeftButtonDown="Border_MouseLeftButtonDown"/>
            <Border Background="Yellow" Height="30" Margin="10" 
                    MouseLeftButtonDown="Border_MouseLeftButtonDown"/>
            <Border Background="Green" Height="30" Margin="10" 
                    MouseLeftButtonDown="Border_MouseLeftButtonDown"/>
            <Border Background="Blue" Height="30" Margin="10" 
                    MouseLeftButtonDown="Border_MouseLeftButtonDown"/>
            <Border Background="Purple" Height="30" Margin="10"
                    MouseLeftButtonDown="Border_MouseLeftButtonDown"/>
        </StackPanel>

        <!--AllowDrop:允许接受拖拽-->
        <Grid Grid.Column="1">
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition />
            </Grid.RowDefinitions>
            <StackPanel Background="Transparent" Grid.Row="0"
                        AllowDrop="True"
                        DragEnter="StackPanel_DragEnter" 
                        DragLeave="StackPanel_DragLeave"
                        DragOver="StackPanel_DragOver"
                        Drop="StackPanel_Drop"/>
            <StackPanel Background="Transparent" Grid.Row="1"
                        AllowDrop="True"
                        DragEnter="StackPanel_DragEnter" 
                        DragLeave="StackPanel_DragLeave"
                        DragOver="StackPanel_DragOver"
                        Drop="StackPanel_Drop"/>
        </Grid>

    </Grid>
</Window>

C#事件处理:

using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace XH.EventLesson
{
    /// <summary>
    /// DragDropEventWindow.xaml 的交互逻辑
    /// </summary>
    public partial class DragDropEventWindow : Window
    {
        public DragDropEventWindow()
        {
            InitializeComponent();
        }

        private void StackPanel_DragEnter(object sender, DragEventArgs e)
        {
            (sender as StackPanel).Background = Brushes.LightGray;
            Debug.WriteLine("==============StackPanel_DragEnter==============");
        }

        private void StackPanel_DragLeave(object sender, DragEventArgs e)
        {
            (sender as StackPanel).Background = Brushes.Transparent;
            Debug.WriteLine("==============StackPanel_DragLeave==============");
        }

        private void StackPanel_DragOver(object sender, DragEventArgs e)
        {
            Debug.WriteLine("==============StackPanel_DragOver==============");
        }

        private void StackPanel_Drop(object sender, DragEventArgs e)
        {
            Debug.WriteLine("==============StackPanel_Drop==============");

            // 直接传入border
            //FrameworkElement ctl = (FrameworkElement)e.Data.GetData(typeof(Border));
            //(ctl.Parent as StackPanel).Children.Remove(ctl);
            //(sender as StackPanel).Children.Add(ctl);

            // 传入背景色然后绘制新的border
            string brush = (string)e.Data.GetData(typeof(string));
            Border border = new Border()
            {
                Height = 30,
                Margin = new Thickness(10),
                Background = (Brush)new BrushConverter().ConvertFromString(brush),
            };
            border.MouseLeftButtonDown += Border_MouseLeftButtonDown;
            (sender as StackPanel).Children.Add(border);
        }

        private void Border_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            Border border = sender as Border;
            // 开始一个拖动处理 准备相关数据
            // DragDropEffects 只关注鼠标状态和显示 不负责拖拽对象
            // DragDrop.DoDragDrop(sender, sender, DragDropEffects.Move);
            DragDrop.DoDragDrop(border, border.Background.ToString(), DragDropEffects.Move);
        }
    }
}

效果:实现拖拽功能

Touch与多点触控事件

行为对象

行为对象的定义

行为并不是WPF中的核心的部分,是Expression Blend的设计特性。使用行为的地方,也是可以使用触发器取代的。

行为对象的使用

C#中进行对象的封装:

using Microsoft.Xaml.Behaviors;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace XH.EventLesson
{
    /// <summary>
    /// BehaviorWindow.xaml 的交互逻辑
    /// </summary>
    public partial class BehaviorWindow : Window
    {
        public BehaviorWindow()
        {
            InitializeComponent();
        }
    }
    // 创建一个行为类 用来封装事件逻辑:对象移动的事件逻辑

    public class DragMoveBehavior:Behavior<FrameworkElement>
    {
        private Point start_point_border;
        private Point start_point_canvas;
        private bool is_moving_border = false;
        private bool is_moving_canvas = false;
        private double start_x_border, start_y_border, start_x_canvas, start_canvas;
        // 执行当前行为所依附的对象的事件挂载
        protected override void OnAttached()
        {
            base.OnAttached();

            // AssociatedObject:所依附的对象
            AssociatedObject.MouseLeftButtonDown += AssociatedObject_MouseLeftButtonDown;
            AssociatedObject.MouseMove += AssociatedObject_MouseMove; 
            AssociatedObject.MouseLeftButtonUp += AssociatedObject_MouseLeftButtonUp; 
        }
        // 
        protected override void OnDetaching()
        {
            base.OnDetaching();

            AssociatedObject.MouseLeftButtonDown -= AssociatedObject_MouseLeftButtonDown;
            AssociatedObject.MouseMove -= AssociatedObject_MouseMove;
            AssociatedObject.MouseLeftButtonUp -= AssociatedObject_MouseLeftButtonUp;
        }

        private void AssociatedObject_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            is_moving_border = false;

            // 释放控件鼠标强制捕捉
            Mouse.Capture(null);
            //this.border.ReleaseMouseCapture();
            e.Handled = true;
        }

        private void AssociatedObject_MouseMove(object sender, MouseEventArgs e)
        {
            if (!is_moving_border) return;

            // 光标移动后 在canvas上的当前位置
            Point p = e.GetPosition(AssociatedObject.Parent as Canvas);
            double offset_x = p.X - start_point_border.X;
            double offset_y = p.Y - start_point_border.Y;

            //Canvas.SetLeft(this.border, offset_x + start_x);
            //Canvas.SetTop(this.border, offset_y + start_y);
            // 移动的差值是光标开始和移动的数值
            Canvas.SetLeft(AssociatedObject, offset_x + start_x_border);
            Canvas.SetTop(AssociatedObject, offset_y + start_y_border);

            e.Handled = true;
        }

        private void AssociatedObject_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            // 获取光标canvas上的当前位置
            start_point_border = e.GetPosition(AssociatedObject.Parent as Canvas);

            start_x_border = Canvas.GetLeft(AssociatedObject);
            start_y_border = Canvas.GetTop(AssociatedObject);

            is_moving_border = true;

            // 第一种 把对象绑定到光标上 两种处理
            Mouse.Capture(AssociatedObject);

            e.Handled = true;
            // 第二种 强制捕捉鼠标
            //this.border.CaptureMouse();
        }
    }
}

XAML中对行为对象的使用:

<Window x:Class="XH.EventLesson.BehaviorWindow"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  xmlns:local="clr-namespace:XH.EventLesson"
  mc:Ignorable="d"
  xmlns:b ="http://schemas.microsoft.com/xaml/behaviors"
  Title="BehaviorWindow" Height="450" Width="800">
  <Canvas Name="canvas">
    <Border Width="100" Height="30" Background="Orange" Canvas.Left="0" Canvas.Top="0">
      <!--把所需要的事件,包装为Behaviors对象-->
      <b:Interaction.Behaviors>
        <local:DragMoveBehavior />
      </b:Interaction.Behaviors>
    </Border>
    <Border Width="100" Height="30" Background="Green" Canvas.Left="100" Canvas.Top="30">
      <b:Interaction.Behaviors>
        <local:DragMoveBehavior />
      </b:Interaction.Behaviors>
    </Border>
    <Label Content="Label" Width="100" Height="30" Background="Gray" Canvas.Left="0" Canvas.Top="30">
      <b:Interaction.Behaviors>
        <local:DragMoveBehavior />
      </b:Interaction.Behaviors>
    </Label>
    <!--目前封装的Behaviors不适用button-->
  </Canvas>
</Window>

可以实现自由拖拽功能

目前封装的Behaviors不适用button:

因为Button中的MouseLeftButtonDown事件,被Click给拦截了。

Demo

实现色块拖动功能

XAML代码:

<Canvas x:Name="canvas" Background="Transparent"
        MouseLeftButtonDown="canvas_MouseLeftButtonDown"
        MouseLeftButtonUp="canvas_MouseLeftButtonUp"
        MouseMove="canvas_MouseMove">
    <!--在对象(Border)上的鼠标的按下 MouseLeftButtonDown
        移动鼠标 MouseMove
        释放鼠标 MouseLeftButtonUp-->
    <Border Width="120" Height="40" Background="Orange"
            Canvas.Left="50" Canvas.Top="50"
            MouseLeftButtonDown="Border_MouseLeftButtonDown"
            MouseMove="Border_MouseMove"
            MouseLeftButtonUp="Border_MouseLeftButtonUp"/>
    
    <Border Width="120" Height="40" Background="Green"
            Canvas.Left="150" Canvas.Top="150"
            MouseLeftButtonDown="Border_MouseLeftButtonDown"
            MouseMove="Border_MouseMove"
            MouseLeftButtonUp="Border_MouseLeftButtonUp"/>
</Canvas>

C#事件处理:

private Point start_point;
private bool is_moving = false;
private double start_x, start_y;
private void Border_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    Border border = (Border)sender;
    // 获取光标canvas上的当前位置
    start_point = e.GetPosition(this.canvas);

    start_x = Canvas.GetLeft(border);
    start_y = Canvas.GetTop(border);

    is_moving = true;

    // 第一种 把对象绑定到光标上 两种处理
    Mouse.Capture(border);
    // 第二种 强制捕捉鼠标
    //this.border.CaptureMouse();
}

private void Border_MouseMove(object sender, MouseEventArgs e)
{
    Border border = (Border)sender;
    if (is_moving)
    {
        // 光标移动后 在canvas上的当前位置
        Point p = e.GetPosition(this.canvas);
        double offset_x = p.X - start_point.X;
        double offset_y = p.Y - start_point.Y;

        //Canvas.SetLeft(this.border, offset_x + start_x);
        //Canvas.SetTop(this.border, offset_y + start_y);
        // 移动的差值是光标开始和移动的数值
        Canvas.SetLeft(border, offset_x + start_x);
        Canvas.SetTop(border, offset_y + start_y);
    }
}

private void Border_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
    is_moving = false;

    // 释放控件鼠标强制捕捉
    Mouse.Capture(null);
    //this.border.ReleaseMouseCapture();
}

效果:能实现色块根据鼠标拖动效果:

实现在canvas中画方块:

XAML代码:

<Canvas x:Name="canvas" Background="Transparent"
  MouseLeftButtonDown="canvas_MouseLeftButtonDown"
  MouseLeftButtonUp="canvas_MouseLeftButtonUp"
  MouseMove="canvas_MouseMove"
  ButtonBase.Click="canvas_Click">
</Canvas>

C#事件处理:

Rectangle rectangle = new Rectangle()
{
    Stroke = Brushes.Red,
    StrokeDashArray = new DoubleCollection { 2, 2 },
    StrokeThickness = 1,
};
private Point current_point;
private void canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    start_point = e.GetPosition(this.canvas);

    this.canvas.Children.Add(rectangle);

    Canvas.SetLeft(rectangle, start_point.X);
    Canvas.SetTop(rectangle, start_point.Y);

    // 初始化矩形
    rectangle.Width = 0;
    rectangle.Height = 0;

    is_moving = true;
}

private void canvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
    is_moving = false;

    this.canvas.Children.Remove(rectangle);
}

private void canvas_MouseMove(object sender, MouseEventArgs e)
{
    if (!is_moving) return;

    current_point = e.GetPosition(this.canvas);

    rectangle.Width = (current_point.X - start_point.X) < 0 ? 0 : current_point.X - start_point.X;
    rectangle.Height = (current_point.Y - start_point.Y) < 0 ? 0: current_point.Y - start_point.Y;
}

效果:实现画矩形

标签:sender,void,AssociatedObject,private,start,事件,WPF,border
From: https://blog.csdn.net/qq_48148522/article/details/140560693

相关文章

  • WPF customize line with sharp arrow and direction
    //CustomizeLineArrowusingSystem;usingSystem.Collections.Generic;usingSystem.ComponentModel;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;usingSystem.Windows.Media;usingSystem.Windows.Shapes;usingSystem.Windows;namespac......
  • WPF 集合通知更改
    集合通知更改,ObservableCollection。属性通知更改,适合单个属性,如果是多个属性的集合数据,使用ObservableCollection。 publicpartialclassButtonWindow:Window{ObservableCollection<Students>infos;publicButtonWindow(){......
  • C# WPF现代化开发:绑定、模板与动画进阶
    ......
  • WPF控件结构与Content理解
    WPF控件结构WPF中控件继承图我们平时所用的容器如Grid、StackPanel等都是继承Panel控件类型分为3组:内容控件、Items控件、TextBoxBase如何理解Content?凡是继承ContentControl的控件,定义内容为Content,除了TextBlock用text以外,大部分都是用Content设置显示类容。一个窗......
  • WPF 命令Command
    MVVM的目的是为了最大限度地降低了Xaml文件和CS文件的合度,分离界面和业务逻辑,所以我们要尽可能的在View后台不写代码。但是这个例子中,我们将更新ViewModel的代码写在了View里。我们能否把按钮的响应处理代码也不写在后台代码里呢?WPF引入Command(命令),通过为Button设置Command来......
  • WPF 绑定
    绑定就是Binding,是控件和数据之间交互的类。source={binding}和source={bindingRelativeSource={RelativeSourceself},Path=DataContext}效果相同。例如:直接绑定数据源前台xaml界面<Grid><StackPanelOrientation="Vertical"><TextBlock......
  • WPF Animation 动画变化值的监控
    WPF动画XXXAnimation即关键类继承制AnimationBase的动画类线性插值动画主要属性FromToDurationAcceleratorDecceleratorFillBehavior等这些常用属性里不做介绍,主要介绍一下几个故事板属性,以备忘记.名称说明Completed动画到达终点时触发,该事件中可以......
  • WPF 触发器
    一、样式触发器样式触发器可以在指定的控件属性满足某种条件后进行一些样式的变换,当触发条件不满足时恢复原样。样式触发器的简单使用<Window.Resources><Stylex:Key="checkBoxStyle"TargetType="CheckBox"><Style.Triggers><TriggerProperty="......
  • WPF 窗体关闭的方式
    1.Close();关闭当前窗口在WPF应用程序的关闭是有ShutdownMode属性设置,具有3中枚举类型的值:1)OnLastWindowClose(默认值)---应用程序最后一个窗体关闭时关闭应用程序2)OnMainWindowClose---应用程序主窗体关闭时关闭应用程序3)OnxplicitShutdown---显示调用关闭这......
  • WPF KeyDown MVVM Via Behavior
    <behavior:Interaction.Triggers><behavior:EventTriggerEventName="KeyDown"><behavior:CallMethodActionMethodName="Window_KeyDown"TargetObject="{Binding}"/></behavior:EventTrigger>......