C# WPF MVVM 实战 – 5- 用绑定,通过 VM 设置 View 的控件焦点
本文介绍在 MVVM 中,如何用 ViewModel 控制焦点。
这焦点设置个东西嘛,有些争论。就是到底要不要用 ViewModel 来控制视图的键盘输入焦点。这里不讨论,假设你就是要通过 VM,设置输入焦点在哪里。
MSDN 有解释关于 Focus 的,还有 FocusManager,点击这里打开。不知道的话建议你先看看,只求结果的可以直接看下面代码,抄就是了。这次,初级的解释全部略过,直接说做法,看不懂的请留言。做法很多,大概两种比较符合 MVVM 模式:
1. DataTrigger 设置 FocusedElement
Style 中写 Trigger,DataTrigger,值变化触发设置 FocusManager 的 FocusedElement。
XAML:
<Grid><Grid.Style><Style><Style.Triggers><DataTrigger Binding="{Binding Path=ScanFtBarCodeNow}" Value="True"><Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName=FtNoTextBox}"/></DataTrigger></Style.Triggers></Style></Grid.Style><TextBox name="FtNoTextBox"/></Grid>
注意:放置 Style 的位置要注意。一层又一层 Grid 的话,FocusManager 单单设置 FocusedElement 为 TextBox 不足够。原因在 MSDN 有说明,不重复。
2. Attached Property
使用 Attached Property 为控件加属性,值变化触发 CallBack,然后 UIElement.Focus()。所谓值变化,比如,bool 变为 True 。
CODE:
publicstaticclass FocusBehavior {
publicstaticbool GetIsFocused(DependencyObject obj) {
return (bool)obj.GetValue(IsFocusedProperty);
}
publicstaticvoid SetIsFocused(DependencyObject obj, bool value) {
obj.SetValue(IsFocusedProperty, value);
}
publicstaticreadonly DependencyProperty IsFocusedProperty =
DependencyProperty.RegisterAttached(
"IsFocused",
typeof(bool),
typeof(FocusBehavior),
new UIPropertyMetadata(false, (s, e) => {
var sender = (UIElement)s;
if ((bool)e.NewValue) {
sender.Focus();
Keyboard.Focus(sender);
}
})
);
}
XAML:
<TextBox local:FocusBehavior.IsFocused="{Binding Path=ScanBarCodeNow}"/>
这做法虽然简单,但实际绑定的并非 UIElement.IsFocused 这只读属性,看CallBack 代码就知道,两个Focus() 都只是方法。界面操作焦点离开此控件时候,DependencyProperty 的值不会变化。后果是,设置一次 true 后,属性值 true,焦点离开它依然是 true,你再设置它 true,会被认定为值无变化,CallBack 没有执行,Focus() 不会运行。Workaround:先设 false 再设 true。
好傻吧。改一下,虽然 IsFocus 是只读无法直接绑定去改它,但可以把 GotFocus 和 LostFocus 事件接上此 Attached Property,触发变更 DependencyProperty 的值,使它变成双向绑定。
using System.Collections.Generic;
using System.Windows;
using System.Windows.Input; namespace Lepton_Practical_MVVM_5 {
publicstaticclass FocusBehavior {
privatestatic Dictionary<UIElement, RoutedEventHandler> handlers =new Dictionary<UIElement, RoutedEventHandler>();
publicstaticbool? GetIsFocused(DependencyObject obj) {
return (bool?)obj.GetValue(IsFocusedProperty);
}
publicstaticvoid SetIsFocused(DependencyObject obj, bool? value) {
obj.SetValue(IsFocusedProperty, value);
}
publicstaticreadonly DependencyProperty IsFocusedProperty =
DependencyProperty.RegisterAttached(
"IsFocused",
typeof(bool?),
typeof(FocusBehavior),
new UIPropertyMetadata() {
DefaultValue =null,
PropertyChangedCallback =
(s, e) => {
UIElement sender = (UIElement)s;
RoutedEventHandler x;
if (!handlers.TryGetValue(sender, out x)) {
Attach(sender);
}
if ((bool)e.NewValue) {
sender.Focus();
Keyboard.Focus(sender);
}
}
});
privatestaticvoid Attach(UIElement sender) {
RoutedEventHandler handler = (s, e) => {
UIElement ui = (UIElement)s;
if (e.RoutedEvent == UIElement.GotFocusEvent) {
ui.SetValue(IsFocusedProperty, true);
}
if (e.RoutedEvent == UIElement.LostFocusEvent) {
ui.SetValue(IsFocusedProperty, false);
}
};
sender.GotFocus += handler;
sender.LostFocus += handler;
handlers.Add(sender, handler);
}
}
}
Dictionary 为了记下已连接的 Handler ,以免重复加入。
XAML:
<Window x:Class="Lepton_Practical_MVVM_5.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Lepton_Practical_MVVM_5"
Title="MainWindow" Height="350" Width="525"><Grid><TextBox local:FocusBehavior.IsFocused="{Binding Path=IsTextBox1Focus,Mode=TwoWay}" Height="23" HorizontalAlignment="Left" Margin="49,54,0,0" Name="textBox1" VerticalAlignment="Top" Width="120"/></Grid></Window>
点击这里下载Attached Property 版本的代码。
这做法是只有加句柄没有移除,你有情况需要移除的话,自己改吧。
我在这群里,欢迎加入交流:
开发板玩家群 578649319
硬件创客 (10105555)
C# WPF MVVM 实战 – 5- 用绑定,通过 VM 设置 View 的控件焦点的更多相关文章
- 笔记03 wpf 在MVVM模式下怎样在Viewmodel里面获得view的控件对象
转自http://blog.csdn.net/qing2005/article/details/6601199http://blog.csdn.net/qing2005/article/detail ...
- WPF编程,通过Double Animation同时动态缩放和旋转控件的一种方法。
原文:WPF编程,通过Double Animation同时动态缩放和旋转控件的一种方法. 版权声明:我不生产代码,我只是代码的搬运工. https://blog.csdn.net/qq_4330793 ...
- C# WPF 低仿网易云音乐(PC)Banner动画控件
原文:C# WPF 低仿网易云音乐(PC)Banner动画控件 由于技术有限没能做到一模一样的动画,只是粗略地做了一下.动画有点生硬,还有就是没做出网易云音乐的立体感.代码非常简单粗暴,而且我也写有很 ...
- WPF 程序如何跨窗口/跨进程设置控件焦点
原文:WPF 程序如何跨窗口/跨进程设置控件焦点 WPF 程序提供了 Focus 方法和 TraversalRequest 来在 WPF 焦点范围内转移焦点.但如果 WPF 窗口中嵌入了其他框架的 U ...
- C# WPF MVVM 实战 – 4 - 善用 IValueConverter
IValueConverter,做 WPF 的都应该接触过,把值换成 Visibility .Margin 等等是最常见的例子,也有很多很好的博文解释过用法.本文只是解释一下,MVVM 中一些情景. ...
- wpf mvvm datagrid DataGridTemplateColumn的绑定无效的可能原因之一!
昨天在mvvm wpf的开发中遇到一个问题,绑定不起作用,编辑阶段没问题也没有提示找不到对应的绑定,但是在运行之后却不起作用,查了很多资料,说法不一,有些是要删除datagrid的一行,直接绑定del ...
- WPF DataGrid列设置为TextBox控件的相关绑定
在wpf的DataGrid控件中,某一列的数据模板为TextBox控件的话,绑定Text="{Binding TxtSn, UpdateSourceTrigger=PropertyChang ...
- WPF学习笔记(四):AvalonEdit 代码高亮编辑控件专题
AvalonEdit 是一个基于 WPF 的文本编辑器组件.它是由 Daniel Grunwald 为 SharpDevelop 编写的.从 5.0 版开始,AvalonEdit 根据MIT许可证发布 ...
- WPF系列之二:解耦View层控件事件与ViewModel层事件的响应
以前的做法: 1.当项目的时间比较紧迫的时候,对UI层中控件的事件的处理,往往采取的是类似Winform中最简单的做法,直接做一个事件的Handler直接去调用VM层的方法. 2.控件只有一个Comm ...
随机推荐
- V4L2应用程序框架-二【转】
本文转载自:http://blog.csdn.net/tommy_wxie/article/details/11371439 V4L2驱动框架 主设备号: 81 次设备号: 0-63 64 ...
- VMware中安装CentOS7网络配置静态IP地址,常用配置和工具安装
VMware中安装CentOS7网络配置静态IP地址,常用配置和工具安装在阿里云开源镜像地址下载镜像Index of /centos/7.2.1511/isos/x86_64/http://mirro ...
- linux下配置环境变量【原创】
用户目录下的.profile, 你只需要在用户目录下,创建bin目录,在里面放入你想要执行的可执行文件,就可以在命令行下就可以使用了 # ~/.profile: executed by the com ...
- Linux workqueue疑问【转】
转自:http://blog.csdn.net/angle_birds/article/details/9387365 各位大神,你们好.我在使用workqueue的过程中遇到一个问题. 项目采用uC ...
- flex 调用gp服务
同步异步说明: gp服务分为同步和异步两种模式,两者的区别是:同步:适合于快速的处理,数据量较小,本质区别在于同步模式,服务器处理之后,处理结果并不在服务器端保存,而是将结果发送至客户端,由客户端去显 ...
- ecshop后台增加模板页的方法
CShop的动态模板机制是一个非常灵活的系统,管理员可以在后台根据自己的要求调整模板模块的显示位置.本文详细讲解了如何修改ECSHOP内部结构使得用户可以添加自己的模板页从而方便灵活的使用系统自带的模 ...
- 浅谈mysql mvcc
以下为个人理解,如有错误,还望指正!! mysql的大多数事务型存储引擎实现的都不是简单的行级锁,基于提升并发性能的考虑,他们一般都同时实现了多版本并发控制,可以认为MVCC是行级锁的一个变种,但是它 ...
- ACM题目————玩转二叉树
给定一棵二叉树的中序遍历和前序遍历,请你先将树做个镜面反转,再输出反转后的层序遍历的序列.所谓镜面反转,是指将所有非叶结点的左右孩子对换.这里假设键值都是互不相等的正整数. 输入格式: 输入第一行给出 ...
- Python time clock()方法
描述 Python time clock() 函数以浮点数计算的秒数返回当前的CPU时间.用来衡量不同程序的耗时,比time.time()更有用. 这个需要注意,在不同的系统上含义不同.在UNIX系统 ...
- 理解 Android Build 系统
在配置了以上的文件之后,便可以编译出我们新添加的设备的系统镜像了. 首先,调用“source build/envsetup.sh”该命令的输出中会看到 Build 系统已经引入了刚刚添加的 vendo ...