通常のプロパティの代わりにネストされたプロパティが使用されている場合、 ICommand.CanExecutes に常に新しい値ではなく以前の値が含まれる理由を理解するのに苦労しました。
問題は以下で説明されていますが、ビューモデルでプロパティを作成し、モデルの対応するプロパティにフックする何らかの形式の「ファサード」パターンを使用する以外に、これを修正する方法を真剣に理解できません。
または、いまいましい CommandManager.RequerySuggested イベントを使用します。これが最適ではない理由は、メニューを数えるだけで 30 を超えるコマンドがビューに表示され、何かが変更されるたびにすべての CanExecute が更新される場合、すべてのメニュー項目/ボタンが更新されるまでに数秒かかるためです。以下の例をコマンド マネージャーと共に 1 つのコマンドとボタンだけで使用しても、ボタン自体を有効/無効にするのに約 500 ミリ秒かかります。
私が考えることができる唯一の理由は、CanExecute が起動される前に CommandParameter バインディングが更新されないことです。それについては何もできないと思います。
前もって感謝します :!
例えば
この基本的なビューモデルがあるとしましょう
public class BasicViewModel : INotifyPropertyChanged
{
private string name;
public string Name
{
get { return name; }
set {
this.name = value;
RaisePropertyChanged("Name");
Command.RaiseCanExecuteChanged();
}
}
private Project project;
public Project Project
{
get { return project; }
set {
if (project != null) project.PropertyChanged -= ChildPropertyChanged;
if (value != null) value.PropertyChanged += ChildPropertyChanged;
project = value;
RaisePropertyChanged("Project");
}
}
private void ChildPropertyChanged(object sender, PropertyChangedEventArgs e) {
Command.RaiseCanExecuteChanged();
}
public DelegateCommand<string> Command { get; set; }
public BasicViewModel()
{
this.Project = new Example.Project();
Command = new DelegateCommand<string>(this.Execute, this.CanExecute);
}
private bool CanExecute(string arg) {
return !string.IsNullOrWhiteSpace(arg);
}
private void Execute(string obj) { }
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName = null) {
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
そしてこのモデル
public class Project : INotifyPropertyChanged
{
private string text;
public string Text
{
get { return text; }
set
{
text = value;
RaisePropertyChanged("Text");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName = null)
{
var handler = this.PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
私の見解では、このテキストボックスとボタンがあります。
<Button Content="Button" CommandParameter="{Binding Path=Project.Text}" Command="{Binding Path=Command}" />
<TextBox Text="{Binding Path=Project.Text, UpdateSourceTrigger=PropertyChanged}" />
テキストボックスに何かを入力するたびに CanExecute が呼び出されますが、パラメーターは常に前の値に設定されます。テキストボックスに 'H' と書くと、パラメータを NULL に設定して CanExecute が起動されます。次に「E」と書きます。テキストボックスに「HE」が含まれ、CanExecute が再び起動します。今回はパラメータを'H'のみに設定。
奇妙な理由で、パラメーターは常に以前の値に設定され、Project.Text を確認すると「HE」に設定されていますが、パラメーターはまだ「H」にのみ設定されています。
コマンドパラメータを
CommandParameter="{Binding Path=Name}"
と Textbox.Text へ
Text={Binding Path=Name, UpdateSourceTrigger=PropertyChanged}"
すべてが完璧に機能します。CanExecute パラメーターには、以前の値ではなく常に最新の値が含まれます。