我在项目Master
,Person
和Command
中有三个班级。 Master
有两个属性,一个构造函数,并覆盖了ToString
:
class Master {
public string FirstName { get; set; }
public string LastName { get; set; }
public Master(string FirstName, string LastName) {
this.FirstName = FirstName;
this.LastName = LastName;
}
public override string ToString() {
return FirstName + " " + LastName;
}
}
Command
是ICommand
class Command : ICommand {
Func<object, bool> CanDo { get; set; }
Action<object> Do { get; set; }
public event EventHandler CanExecuteChanged;
public Command(Func<object, bool> CanDo, Action<object> Do) {
this.CanDo = CanDo;
this.Do = Do;
CommandManager.RequerySuggested += (o, e) => Evaluate();
}
public bool CanExecute(object parameter) => CanDo(parameter);
public void Execute(object parameter) => Do(parameter);
public void Evaluate() => CanExecuteChanged?.Invoke(null, EventArgs.Empty);
}
和Person
具有两个属性,已实现INotifyPropertyChanged
,是ObservableCollection<Master>
和使用Command
:
class Person : ObservableCollection<Master>, INotifyPropertyChanged {
string firstName, lastName;
public string FirstName {
get => firstName;
set { firstName = value; OnPropertyChanged(); }
}
public string LastName {
get => lastName;
set { lastName = value; OnPropertyChanged(); }
}
public Command AddToList { get; set; }
public new event PropertyChangedEventHandler PropertyChanged;
public Person() {
AddToList = new Command(CanDo, Do);
}
void OnPropertyChanged([CallerMemberName] string name = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
bool CanDo(object para) => !string.IsNullOrEmpty(firstName) && !string.IsNullOrEmpty(lastName);
void Do(object para) {
Add(new Master(firstName, firstName));
FirstName = LastName = null;
}
}
在xaml上,我有这些:
<Window ...>
<Window.Resources>
<local:Person x:Key="Person"/>
</Window.Resources>
<Grid DataContext="{StaticResource Person}">
<StackPanel>
<TextBox Text="{Binding FirstName}"/>
<TextBox Text="{Binding LastName}"/>
<Button Content="Click" Command="{Binding AddToList}"/>
<ListView ItemsSource="{Binding}"/>
</StackPanel>
</Grid>
</Window>
启动应用程序以在其中键入内容后,我必须单击绑定到TextBox
的第一个FirstName
,通过按 Tab 可以输入第二个TextBox
,如果我再按一次 Tab ,它不是聚焦Button
而是回到第一个TextBox
,所以我必须按 Tab < / kbd>两次进入Button
,然后按 Enter 或 Space ,可以将项目添加到ListView
中。
在这一点上,我不确定重点是什么,我必须再按一次 Tab 才能到达第一个TextBox
。如果我按了 Tab ,则在第一个和第二个TextBoxes
中键入了更多文本后,它不再聚焦Button
或第一个TextBox
选择了{{1} },所以我必须三次按 Tab 才能进入ListView
!
我想在应用启动时首先关注Button
,然后在第二TextBox
上点击 Tab 后,我希望它转到TextBox
并排除Button
来自焦点。我尝试在ListView
中设置Focusable="False"
,KeyboardNavigation.IsTabStop="False"
,IsTabStop="False"
,但是这些无效!我还尝试过在ListView
和TabIndex
上设置TextBoxes
,如下所示:
Button
这些也不起作用!
答案 0 :(得分:1)
您遇到的问题是,在远离第二个文本框的位置,它需要确定将焦点放置在何处。但是,在该时间点,该命令仍被禁用,因为由于文本框中的值尚未到达视图模型中而无法执行,因此该命令无法执行。该值在焦点移动后到达。
解决此问题的一种方法是更改第二个文本框的绑定,以便在每次更改值时更新ViewModel。将以下子句添加到该绑定:
tiempo =...
此处有更多详细信息... https://docs.microsoft.com/en-us/dotnet/framework/wpf/data/how-to-control-when-the-textbox-text-updates-the-source
现在,每当您键入一个字符时,该命令就会重新考虑是否可以执行该命令。
答案 1 :(得分:1)
简短答案:
在绑定上设置UpdateSourceTrigger=PropertyChanged
:
<TextBox Text="{Binding FirstName, UpdateSourceTrigger=PropertyChanged}"/>
<TextBox Text="{Binding LastName, UpdateSourceTrigger=PropertyChanged}"/>
我怀疑正在发生的事情是WPF在评估CanExecute命令之前正在评估下一个选项卡的位置,因此,在确定要跳转至下一个选项卡的位置时,该按钮仍处于禁用状态,因此唯一要做的就是回到第一个文本框。
UpdateSourceTrigger告诉WPF评估每次按键时的绑定,而不是焦点改变时的绑定,这意味着在按钮需要工作时,按钮已正确启用。