C# WPF MVVM 实战 – 5- 用绑定,通过 VM 设置 View 的控件焦点
2017-08-28 15:34
489 查看
原文链接:http://www.cnblogs.com/leptonation/p/3292961.html
本文介绍在 MVVM 中,如何用 ViewModel 控制焦点。
这焦点设置个东西嘛,有些争论。就是到底要不要用 ViewModel 来控制视图的键盘输入焦点。这里不讨论,假设你就是要通过 VM,设置输入焦点在哪里。
MSDN 有解释关于 Focus 的,还有 FocusManager,点击这里打开。不知道的话建议你先看看,只求结果的可以直接看下面代码,抄就是了。这次,初级的解释全部略过,直接说做法,看不懂的请留言。做法很多,大概两种比较符合
MVVM 模式:
1. DataTrigger 设置 FocusedElement
Style 中写 Trigger,DataTrigger,值变化触发设置 FocusManager 的 FocusedElement。
XAML:
2. Attached Property
使用 Attached Property 为控件加属性,值变化触发 CallBack,然后 UIElement.Focus()。所谓值变化,比如,bool 变为 True 。
CODE:
这做法虽然简单,但实际绑定的并非 UIElement.IsFocused 这只读属性,看CallBack 代码就知道,两个Focus() 都只是方法。界面操作焦点离开此控件时候,DependencyProperty 的值不会变化。后果是,设置一次 true 后,属性值 true,焦点离开它依然是 true,你再设置它 true,会被认定为值无变化,CallBack 没有执行,Focus() 不会运行。Workaround:先设 false 再设 true。
好傻吧。改一下,虽然 IsFocus 是只读无法直接绑定去改它,但可以把 GotFocus 和 LostFocus 事件接上此 Attached Property,触发变更 DependencyProperty 的值,使它变成双向绑定。
Dictionary 为了记下已连接的 Handler ,以免重复加入。
XAML:
本文介绍在 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>源代码下载
相关文章推荐
- C# WPF MVVM 实战 – 5- 用绑定,通过 VM 设置 View 的控件焦点
- Jquery如何序列化form表单数据为JSON对象 C# ADO.NET中设置Like模糊查询的参数 从客户端出现小于等于公式符号引发检测到有潜在危险的Request.Form 值 jquery调用iframe里面的方法 Js根据Ip地址自动判断是哪个城市 【我们一起写框架】MVVM的WPF框架(三)—数据控件 设计模式之简单工厂模式(C#语言描述)
- C#中,datagridview与sql数据源绑定后,通过控件更改数据如何自动回写更新到数据源
- (WPF) MVVM: 动态添加控件及绑定。
- c# 通过属性设置控件的显示与否
- 如何通过代码设置WPF控件的字体,颜色
- WPF 如何在后台进行控件属性的绑定MVVM
- WPF利用通过父控件属性来获得绑定数据源RelativeSource
- C#中通过回车跳转到控件的焦点
- WPF设置控件获取键盘焦点时的样式FocusVisualStyle
- Dxexpress 的GridControl控件中一次选择一行并且不显示单元格焦点的设置 (转自C#之旅)
- C# WPF MVVM 实战 – 4 - 善用 IValueConverter
- WPF密码控件PasswordBox之 MVVM绑定使用
- WPF中MVVM模式下控件自有的事件绑定
- C# wpf image绑定viewModel没有显示图片
- C# wpf image绑定viewModel没有显示图片
- C# WPF MVVM 实战 – 2.4 单元测试
- WPF MVVM框架下,VM界面写控件
- MFC中通过控件ID设置控件焦点
- C#中通过回车跳转到控件的焦点