pri*_*kar 124 c# wpf xaml textbox mvvm
在我看来,我有一个TextBox
和一个Button
.
现在我在点击按钮时检查条件,如果条件结果为假,向用户显示消息,然后我必须将光标设置为TextBox
控件.
if (companyref == null)
{
var cs = new Lipper.Nelson.AdminClient.Main.Views.ContactPanels.CompanyAssociation();
MessageBox.Show("Company does not exist.", "Error", MessageBoxButton.OK,
MessageBoxImage.Exclamation);
cs.txtCompanyID.Focusable = true;
System.Windows.Input.Keyboard.Focus(cs.txtCompanyID);
}
Run Code Online (Sandbox Code Playgroud)
上面的代码在ViewModel中.
这CompanyAssociation
是视图名称.
但光标没有设置在TextBox
.
xaml是:
<igEditors:XamTextEditor Name="txtCompanyID"
KeyDown="xamTextEditorAllowOnlyNumeric_KeyDown"
ValueChanged="txtCompanyID_ValueChanged"
Text="{Binding Company.CompanyId,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
Width="{Binding ActualWidth, ElementName=border}"
Grid.Column="1" Grid.Row="0"
VerticalAlignment="Top"
HorizontalAlignment="Stretch"
Margin="0,5,0,0"
IsEnabled="{Binding Path=IsEditable}"/>
<Button Template="{StaticResource buttonTemp1}"
Command="{Binding ContactCommand}"
CommandParameter="searchCompany"
Content="Search"
Width="80"
Grid.Row="0" Grid.Column="2"
VerticalAlignment="Top"
Margin="0"
HorizontalAlignment="Left"
IsEnabled="{Binding Path=IsEditable}"/>
Run Code Online (Sandbox Code Playgroud)
Anv*_*aka 253
让我分三部分回答你的问题.
我想知道你的例子中的"cs.txtCompanyID"是什么?它是TextBox控件吗?如果是,那么你走错了路.一般来说,在ViewModel中对UI进行任何引用都不是一个好主意.你可以问"为什么?" 但这是另一个在Stackoverflow上发布的问题:).
追踪Focus问题的最佳方法是...调试.Net源代码.不开玩笑.它多次为我节省了很多时间.要启用.net源代码调试,请参阅Shawn Bruke的博客.
最后,我用来从ViewModel设置焦点的一般方法是附加属性.我写了非常简单的附加属性,可以在任何UIElement上设置.例如,它可以绑定到ViewModel的属性"IsFocused".这里是:
public static class FocusExtension
{
public static bool GetIsFocused(DependencyObject obj)
{
return (bool) obj.GetValue(IsFocusedProperty);
}
public static void SetIsFocused(DependencyObject obj, bool value)
{
obj.SetValue(IsFocusedProperty, value);
}
public static readonly DependencyProperty IsFocusedProperty =
DependencyProperty.RegisterAttached(
"IsFocused", typeof (bool), typeof (FocusExtension),
new UIPropertyMetadata(false, OnIsFocusedPropertyChanged));
private static void OnIsFocusedPropertyChanged(
DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var uie = (UIElement) d;
if ((bool) e.NewValue)
{
uie.Focus(); // Don't care about false values.
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在在您的视图中(在XAML中),您可以将此属性绑定到ViewModel:
<TextBox local:FocusExtension.IsFocused="{Binding IsUserNameFocused}" />
Run Code Online (Sandbox Code Playgroud)希望这可以帮助 :).如果它没有提到答案#2.
干杯.
Zam*_*tic 68
我知道这个问题现在已被回答了一千次,但我对Anvaka的贡献进行了一些编辑,我认为这将有助于其他有类似问题的人.
首先,我改变了上面的附属物:
public static class FocusExtension
{
public static readonly DependencyProperty IsFocusedProperty =
DependencyProperty.RegisterAttached("IsFocused", typeof(bool?), typeof(FocusExtension), new FrameworkPropertyMetadata(IsFocusedChanged){BindsTwoWayByDefault = true});
public static bool? GetIsFocused(DependencyObject element)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
return (bool?)element.GetValue(IsFocusedProperty);
}
public static void SetIsFocused(DependencyObject element, bool? value)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
element.SetValue(IsFocusedProperty, value);
}
private static void IsFocusedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var fe = (FrameworkElement)d;
if (e.OldValue == null)
{
fe.GotFocus += FrameworkElement_GotFocus;
fe.LostFocus += FrameworkElement_LostFocus;
}
if (!fe.IsVisible)
{
fe.IsVisibleChanged += new DependencyPropertyChangedEventHandler(fe_IsVisibleChanged);
}
if ((bool)e.NewValue)
{
fe.Focus();
}
}
private static void fe_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
var fe = (FrameworkElement)sender;
if (fe.IsVisible && (bool)((FrameworkElement)sender).GetValue(IsFocusedProperty))
{
fe.IsVisibleChanged -= fe_IsVisibleChanged;
fe.Focus();
}
}
private static void FrameworkElement_GotFocus(object sender, RoutedEventArgs e)
{
((FrameworkElement)sender).SetValue(IsFocusedProperty, true);
}
private static void FrameworkElement_LostFocus(object sender, RoutedEventArgs e)
{
((FrameworkElement)sender).SetValue(IsFocusedProperty, false);
}
}
Run Code Online (Sandbox Code Playgroud)
我添加可见性引用的原因是标签.显然,如果您在最初可见选项卡之外的任何其他选项卡上使用附加属性,则在手动聚焦控件之前,附加属性不起作用.
另一个障碍是在失去焦点时创建一种更优雅的方法将底层属性重置为false.这就是丢失焦点事件的来源.
<TextBox
Text="{Binding Description}"
FocusExtension.IsFocused="{Binding IsFocused}"/>
Run Code Online (Sandbox Code Playgroud)
如果有更好的方法来处理可见性问题,请告诉我.
注意:感谢Apfelkuacha建议将BindsTwoWayByDefault放入DependencyProperty中.我很久以前在自己的代码中做过这个,但从未更新过这篇文章.由于此更改,WPF代码中不再需要Mode = TwoWay.
Ada*_*dam 30
我认为最好的方法是保持MVVM原理干净,所以基本上你必须使用随MVVM Light提供的Messenger类,以下是如何使用它:
在您的viewmodel(exampleViewModel.cs)中:编写以下内容
Messenger.Default.Send<string>("focus", "DoFocus");
Run Code Online (Sandbox Code Playgroud)
现在在您的View.cs(不是XAML view.xaml.cs)中在构造函数中编写以下内容
public MyView()
{
InitializeComponent();
Messenger.Default.Register<string>(this, "DoFocus", doFocus);
}
public void doFocus(string msg)
{
if (msg == "focus")
this.txtcode.Focus();
}
Run Code Online (Sandbox Code Playgroud)
这种方法很好,代码较少,维护MVVM标准
小智 18
这些都不能完全适用于我,但为了其他人的利益,这是我最终根据这里已经提供的一些代码编写的.
用法如下:
<TextBox ... h:FocusBehavior.IsFocused="True"/>
Run Code Online (Sandbox Code Playgroud)
实施如下:
/// <summary>
/// Behavior allowing to put focus on element from the view model in a MVVM implementation.
/// </summary>
public static class FocusBehavior
{
#region Dependency Properties
/// <summary>
/// <c>IsFocused</c> dependency property.
/// </summary>
public static readonly DependencyProperty IsFocusedProperty =
DependencyProperty.RegisterAttached("IsFocused", typeof(bool?),
typeof(FocusBehavior), new FrameworkPropertyMetadata(IsFocusedChanged));
/// <summary>
/// Gets the <c>IsFocused</c> property value.
/// </summary>
/// <param name="element">The element.</param>
/// <returns>Value of the <c>IsFocused</c> property or <c>null</c> if not set.</returns>
public static bool? GetIsFocused(DependencyObject element)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
return (bool?)element.GetValue(IsFocusedProperty);
}
/// <summary>
/// Sets the <c>IsFocused</c> property value.
/// </summary>
/// <param name="element">The element.</param>
/// <param name="value">The value.</param>
public static void SetIsFocused(DependencyObject element, bool? value)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
element.SetValue(IsFocusedProperty, value);
}
#endregion Dependency Properties
#region Event Handlers
/// <summary>
/// Determines whether the value of the dependency property <c>IsFocused</c> has change.
/// </summary>
/// <param name="d">The dependency object.</param>
/// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
private static void IsFocusedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// Ensure it is a FrameworkElement instance.
var fe = d as FrameworkElement;
if (fe != null && e.OldValue == null && e.NewValue != null && (bool)e.NewValue)
{
// Attach to the Loaded event to set the focus there. If we do it here it will
// be overridden by the view rendering the framework element.
fe.Loaded += FrameworkElementLoaded;
}
}
/// <summary>
/// Sets the focus when the framework element is loaded and ready to receive input.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
private static void FrameworkElementLoaded(object sender, RoutedEventArgs e)
{
// Ensure it is a FrameworkElement instance.
var fe = sender as FrameworkElement;
if (fe != null)
{
// Remove the event handler registration.
fe.Loaded -= FrameworkElementLoaded;
// Set the focus to the given framework element.
fe.Focus();
// Determine if it is a text box like element.
var tb = fe as TextBoxBase;
if (tb != null)
{
// Select all text to be ready for replacement.
tb.SelectAll();
}
}
}
#endregion Event Handlers
}
Run Code Online (Sandbox Code Playgroud)
Ric*_*h N 11
这是一个旧线程,但似乎没有解决代码解决Anavanka接受的答案的问题:如果您将viewmodel中的属性设置为false,或者如果您将属性设置为是的,用户手动点击其他内容,然后再次将其设置为true.在这些情况下,我无法让Zamotic的解决方案可靠地工作.
将上面的一些讨论结合在一起,给出了下面的代码,我认为这些问题可以解决这些问题:
public static class FocusExtension
{
public static bool GetIsFocused(DependencyObject obj)
{
return (bool)obj.GetValue(IsFocusedProperty);
}
public static void SetIsFocused(DependencyObject obj, bool value)
{
obj.SetValue(IsFocusedProperty, value);
}
public static readonly DependencyProperty IsFocusedProperty =
DependencyProperty.RegisterAttached(
"IsFocused", typeof(bool), typeof(FocusExtension),
new UIPropertyMetadata(false, null, OnCoerceValue));
private static object OnCoerceValue(DependencyObject d, object baseValue)
{
if ((bool)baseValue)
((UIElement)d).Focus();
else if (((UIElement) d).IsFocused)
Keyboard.ClearFocus();
return ((bool)baseValue);
}
}
Run Code Online (Sandbox Code Playgroud)
话虽如此,对于可以在代码隐藏中的一行中完成的事情来说,这仍然很复杂,并且CoerceValue并不是真的意味着以这种方式使用,所以也许代码隐藏是要走的路.
小智 5
就我而言,在我更改 OnIsFocusedPropertyChanged 方法之前,FocusExtension 不起作用。最初的版本仅在调试时工作,当断点停止进程时。在运行时,该过程太快并且什么也没发生。通过这个小小的修改和我们的朋友 Task 的帮助,这在两种情况下都工作得很好。
private static void OnIsFocusedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var uie = (UIElement)d;
if ((bool)e.NewValue)
{
var action = new Action(() => uie.Dispatcher.BeginInvoke((Action)(() => uie.Focus())));
Task.Factory.StartNew(action);
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
105872 次 |
最近记录: |