[解決済み] WPFのCanExecuteを最初に呼び出すとCommandParameterがNULLになる。
質問
WPF と、ItemsControl の DataTemplate 内のボタンにバインドされているコマンドで問題に遭遇しました。シナリオは非常に単純明快です。ItemsControl はオブジェクトのリストにバインドされており、ボタンをクリックすることで、リスト内の各オブジェクトを削除できるようにしたいのです。ボタンはコマンドを実行し、コマンドは削除を行う。CommandParameterは、削除したいオブジェクトにバインドされています。こうすることで、ユーザーが何をクリックしたのかがわかります。ユーザーは、自分自身のオブジェクトしか削除できないはずです。したがって、ユーザーが正しい権限を持っていることを確認するために、Command の "CanExecute" 呼び出しでいくつかのチェックを行う必要があります。
問題は、CanExecute に渡されるパラメーターは、最初に呼び出されたときは NULL であることです - したがって、コマンドを有効/無効にするロジックを実行できません。しかし、常に有効にし、ボタンをクリックしてコマンドを実行すると、CommandParameter は正しく渡されます。つまり、CommandParameterに対するバインディングは機能していることになります。
ItemsControlとDataTemplateのXAMLは以下のようになります。
<ItemsControl
x:Name="commentsList"
ItemsSource="{Binding Path=SharedDataItemPM.Comments}"
Width="Auto" Height="Auto">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Button
Content="Delete"
FontSize="10"
Command="{Binding Path=DataContext.DeleteCommentCommand, ElementName=commentsList}"
CommandParameter="{Binding}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
ご覧の通り、Commentsオブジェクトのリストがあります。DeleteCommentCommandのCommandParameterはCommandオブジェクトにバインドされるようにしたいです。
私の質問は、この問題を経験したことがある人がいるかどうかということです。CanExecute は私の Command で呼び出されますが、パラメーターは初回では常に NULL です - なぜでしょうか?
更新しました。 少し問題を絞り込むことができました。空の Debug ValueConverter を追加して、CommandParameter がデータバインドされたときにメッセージを出力できるようにしました。問題はCanExecuteメソッドがCommandParameterがボタンにバインドされる前に実行されることであることがわかりました。私はCommandParameterをCommandの前に設定しようとしました(提案されたように) - しかし、それはまだうまくいきません。それを制御する方法についての任意のヒント。
更新2です。 バインディングがいつ"done"されたかを検出し、コマンドの再評価を強制できるような方法はありますか? また、コマンド オブジェクトの同じインスタンスにバインドする複数のボタン (ItemsControl の各アイテムに 1 つ) があることは問題でしょうか?
更新 3: 再現したバグをSkyDriveにアップロードしました。 http://cid-1a08c11c407c0d8e.skydrive.live.com/self.aspx/Code%20samples/CommandParameterBinding.zip
どのように解決するのですか?
同じような問題に出くわしたので、信頼できる TriggerConverter を使って解決しました。
public class TriggerConverter : IMultiValueConverter
{
#region IMultiValueConverter Members
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
// First value is target value.
// All others are update triggers only.
if (values.Length < 1) return Binding.DoNothing;
return values[0];
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
この値変換器は、任意の数のパラメータを受け取り、そのうちの最初のパラメータを変換後の値として送り返します。あなたの場合のMultiBindingで使用すると、次のようになります。
<ItemsControl
x:Name="commentsList"
ItemsSource="{Binding Path=SharedDataItemPM.Comments}"
Width="Auto" Height="Auto">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Button
Content="Delete"
FontSize="10"
CommandParameter="{Binding}">
<Button.Command>
<MultiBinding Converter="{StaticResource TriggerConverter}">
<Binding Path="DataContext.DeleteCommentCommand"
ElementName="commentsList" />
<Binding />
</MultiBinding>
</Button.Command>
</Button>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
これを動作させるには、TriggerConverterをリソースとしてどこかに追加する必要がある。これで、CommandParameterの値が利用可能になる前に、Commandプロパティが設定されるようになった。.ではなく、RelativeSource.SelfとCommandParameterにバインドしても同じ効果が得られます。
関連
-
[解決済み] StackPanelの子パネルが下方向に最大限のスペースを埋めるようにするには?
-
[解決済み】WPFコンボボックスのカスタムリストへのバインド
-
[解決済み] WPFでイベント処理のためにリソース辞書の後ろにコードを設定することは可能ですか?
-
[解決済み] XAML ColumnDefinitionの*(アスタリスク)の意味は?
-
[解決済み] テンプレートバインディングとバインディングとは?
-
[解決済み] DataTemplateから親DataContextにアクセスする
-
[解決済み] TwoWayまたはOneWayToSourceバインディングは、読み取り専用プロパティでは機能しません。
-
[解決済み] WPFにDesignModeプロパティはありますか?
-
[解決済み] グリッドの行と列の位置をプログラムで設定する方法
-
[解決済み] WPF : ダイアログをアプリケーションの中心に表示させるには?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] SelectedItem、SelectedValue、SelectedValuePathの違いについて
-
[解決済み] ユーザーコントロールライブラリーとカスタムコントロールライブラリーの違いは何ですか?
-
[解決済み] WPF フォントのぼやけ問題- 解決策
-
[解決済み] 読み取り専用のGUIプロパティをViewModelにプッシュバックする
-
[解決済み] WPFのデータグリッドでセルの編集を無効にするには?
-
[解決済み] WPFのページロードでコンボボックスにデフォルトテキスト"--Select Team -- "を表示するには?
-
[解決済み] DataTemplateから親DataContextにアクセスする
-
[解決済み] グリッドの行と列の位置をプログラムで設定する方法
-
[解決済み] WPFのバインディングモードにはどのようなものがありますか?
-
[解決済み] WPF : ダイアログをアプリケーションの中心に表示させるには?