我有一个控件(GridView
在下面的示例中命名)和一个视图模型,它们通过 2 路绑定对其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 不是我的控件,而是我继承的第 3 方数据网格。当用户编辑记录时,我们会弹出一个窗口,用户在其中编辑记录,然后视图模型刷新数据并使用其 ID 重新选择旧记录。在用户使用网格的过滤功能之前,一切正常。如果对记录的编辑由于过滤器而使该行隐藏,则会发生以下情况:
ValueList
在属性中查看模型集- 网格读取该新列表
- 网格过滤列表
- View Model
SelectedValue
使用位于ValueList
- 网格读取新的
SelectedValue
但将其丢弃,因为它已被过滤掉 - 网格有 SelectedValue = 23 并且视图模型有 SelectedValue = 42
- 用户双击所选行(他看到 23)以编辑记录
- 在
ICommand
视图模型中调用映射到双击 - 查看模型启动编辑窗口,其中包含来自其
SelectedValue
属性的记录 - 用户编辑记录 42 但认为它是 23。