那么如何使用MVVM模式在按钮上单击TextBox?
我创建了一个基于this Answer的简单Testproject,它在第一次点击时起作用,但之后它不再设置Focus。我错过了什么?
XAML(查看)
<Grid>
<TextBox Height='23' HorizontalAlignment='Left' Margin='12,12,0,0' VerticalAlignment='Top' Width='120'
Text='{Binding TheText}'
local:FocusExtension.IsFocused="{Binding IsFocused}"/>
<Button Content='Click' Height='23' HorizontalAlignment='Left' Margin='138,11,0,0' VerticalAlignment='Top' Width='75'
Command='{Binding ClickCommand}'/>
<Button Content='Just to deFocus' Height='28' HorizontalAlignment='Left' Margin='14,44,0,0' Name='button1' VerticalAlignment='Top' Width='199' />
</Grid>
视图模型
public class ViewModel : INotifyPropertyChanged
{
public string TheText { get; set; }
public bool IsFocused { get; set; }
private RelayCommand _clickCommand;
public ICommand ClickCommand
{
get { return _clickCommand ?? (_clickCommand = new RelayCommand(param => this.OnClick())); }
}
private void OnClick()
{
IsFocused = true;
RaisePropertyChanged("IsFocused");
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
#endregion
}
这是一个Download link,有一个准备好去项目(VS2010)的懒人;)
答案 0 :(得分:6)
在覆盖初始默认值后,您的附加属性值永远不会返回false。因此,FocusExtension
课程未在Focus()
上调用TextBox
,因为在您的虚拟机中将PropertyChanged
设置为true时,IsFocused
无需触发。
切换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.
}
到
private static void OnIsFocusedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
var uie = (UIElement)d;
if (!((bool)e.NewValue))
return;
uie.Focus();
uie.LostFocus += UieOnLostFocus;
}
private static void UieOnLostFocus(object sender, RoutedEventArgs routedEventArgs) {
var uie = sender as UIElement;
if (uie == null)
return;
uie.LostFocus -= UieOnLostFocus;
uie.SetValue(IsFocusedProperty, false);
}
<强>更新强>
随着上述变化也确保
local:FocusExtension.IsFocused="{Binding IsFocused}"
切换到
local:FocusExtension.IsFocused="{Binding IsFocused, Mode=TwoWay}"
另一次更新
在Mode=TwoWay
班级开关
FocusExtension
设置为此附加属性的默认值
public static readonly DependencyProperty IsFocusedProperty = DependencyProperty.RegisterAttached(
"IsFocused",
typeof(bool),
typeof(FocusExtension),
new UIPropertyMetadata(
false,
OnIsFocusedPropertyChanged));
到
public static readonly DependencyProperty IsFocusedProperty = DependencyProperty.RegisterAttached(
"IsFocused",
typeof(bool),
typeof(FocusExtension),
new FrameworkPropertyMetadata(
false,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
OnIsFocusedPropertyChanged));
您可以使用上述声明跳过在xaml中明确指定Mode=TwoWay
。
答案 1 :(得分:1)
您应该为lostFocus事件发出命令,当焦点丢失时,将isFocused属性设置为false,然后它将起作用。将交互性和交互图书馆添加到您的项目中,而不是像以下那样编写:
<i:Interaction.Triggers>
<i:EventTrigger EventName="LostFocus">
<ei:CallMethodAction TargetObject="{Binding}" MethodName="OnLostFocus"/>
</i:EventTrigger>
</i:Interaction.Triggers>
并在你的viewModel中写:
public void OnLostFocus()
{IsFocused = false;}
并将RaisePropertyChanged移动到您的属性的setter
答案 2 :(得分:1)
之前我遇到过同样的问题。我做了一个技巧。在OnClick方法中,执行以下操作:
if(IsFocus == true)
IsFocus = false;
IsFocus = true;