コントロール (GridView
以下の例で名前が付けられています) とビュー モデルがあり、それらはプロパティで双方向バインディングによってバインドされていSelectedValue
ます。GridView
を使用して、コントロール内のそのプロパティの特定の値を禁止したいと考えていますCoerceValueCallback
。
バインディングがその無効な値 (この例では 42) を にプッシュするDependencyProperty
と、CoerceValue
メソッドはその値を破棄し、コントロールは以前の値を期待どおりに保持します。残念ながら、DependencyProperty
バインディングは変更されていないため、ビュー モデルのソース値は更新されません。
プロパティ値の変更をキャンセルするときに、ビュー モデルのプロパティをコントロールの値で更新するにはどうすればよいですか?
class ViewModel : INotifyPropertyChanged
{
public int? SelectedValue
{
get { return _selectedValue; }
set
{
_selectedValue = value;
RaisePropertyChanged("SelectedValue");
}
}
private int? _selectedValue;
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string name)
{
var propertyChanged = PropertyChanged;
if (propertyChanged != null)
{
propertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}
class GridView : FrameworkElement
{
public object SelectedValue
{
get { return (object)GetValue(SelectedValueProperty); }
set { SetValue(SelectedValueProperty, value); }
}
public static readonly DependencyProperty SelectedValueProperty =
DependencyProperty.Register("SelectedValue", typeof(object), typeof(GridView),
new PropertyMetadata(null, null, new CoerceValueCallback(CoerceValue)));
private static object CoerceValue(DependencyObject d, object baseValue)
{
// forbid value 42 and return previous value
if (Equals(baseValue, 42))
{
return d.GetValue(GridView.SelectedValueProperty);
}
return baseValue;
}
}
[STAThread]
static void Main()
{
ViewModel vm = new ViewModel();
GridView grid = new GridView();
Binding binding = new Binding("SelectedValue") { Source = vm, Mode = BindingMode.TwoWay };
grid.SetBinding(GridView.SelectedValueProperty, binding);
vm.SelectedValue = 12;
Console.WriteLine("should be 12: {0} = {1}", grid.SelectedValue, vm.SelectedValue);
grid.SelectedValue = 23;
Console.WriteLine("should be 23: {0} = {1}", grid.SelectedValue, vm.SelectedValue);
vm.SelectedValue = 42;
Console.WriteLine("should still be 23: {0} = {1}", grid.SelectedValue, vm.SelectedValue);
}
私が試してみました
var binding = BindingOperations.GetBindingExpression(d,
GridView.SelectedValueProperty);
binding.UpdateSource();
CoerceValue
役に立たない方法で。Dispatcher.CurrentDispatcher.BeginInvoke(updateSource, DispatcherPriority.DataBind);
同様のスタックオーバーフローの質問で提案された前の2行も試しました。
他のアイデアはありますか?
更新:
@Berrylは、ビューモデルでそのロジックを実行する必要があることを提案しました。私は彼に同意します...私ができないことを除いて。上記のコードで単純化しようとした完全な使用例について説明します。
GridView は私のコントロールではなく、継承元のサードパーティ データ グリッドです。ユーザーがレコードを編集すると、ユーザーがレコードを編集するウィンドウがポップアップ表示され、ビュー モデルがデータを更新し、ID を使用して古いレコードを再選択します。ユーザーがグリッドのフィルタリング機能を使用するまで、すべてがうまく機能します。フィルターが原因でレコードの編集によって行が非表示になる場合は、次のようになります。
ValueList
プロパティでモデル セットを表示する- グリッドはその新しいリストを読み取ります
- グリッドはリストをフィルタリングします
- View Model は
SelectedValue
、ValueList
- グリッドはその新しい
SelectedValue
ものを読み取りますが、フィルターで除外されているため破棄します - グリッドには SelectedValue = 23 があり、ビュー モデルには SelectedValue = 42 があります
- ユーザーは、選択した行 (23 が表示されます) をダブルクリックして、レコードを編集します。
ICommand
ダブルクリックにマッピングされた はビューモデルで呼び出されますSelectedValue
ビューモデルは、そのプロパティからのレコードで編集ウィンドウを起動します- ユーザーはレコード 42 を編集しますが、それは 23 だと思います。