gpt4 book ai didi

wpf - 在 DependencyProperty 的 CoerceValueCallback 中取消更新时如何更新绑定(bind)源?

转载 作者:行者123 更新时间:2023-12-03 10:18:08 25 4
gpt4 key购买 nike

我有一个控件(在下面的示例中名为 GridView)和一个 View 模型,它们通过它们的 SelectedValue 上的 2 路绑定(bind)进行绑定(bind)。属性(property)。我想在 GridView 中禁止该属性的某些值通过使用 CoerceValueCallback 进行控制.

当绑定(bind)将该无效值(本例中为 42)插入 DependencyProperty 时, CoerceValue方法丢弃该值,并且控件按预期保留其先前的值。不幸的是,因为 DependencyProperty未更改绑定(bind)不会更新 View 模型中的源值。

取消属性值更改时,如何使用控件中的值更新 View 模型中的属性?

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); 尝试了前两行这是在类似的堆栈溢出问题中提出的。

还有其他想法吗?

更新:

@Berryl 建议我应该在 View 模型中执行该逻辑,我同意他的观点……除了我不能。我将解释我试图在上面的代码中简化的完整用例。

GridView 不是我的控件,而是我继承的第 3 方数据网格。当用户编辑记录时,我们会弹出一个窗口,用户在其中编辑记录,然后 View 模型刷新数据并使用其 ID 重新选择旧记录。在用户使用网格的过滤功能之前,一切正常。如果对记录的编辑由于过滤器而使该行隐藏,则会发生以下情况:
  • ValueList 中查看模型集房产
  • 网格读取该新列表
  • 网格过滤列表
  • 查看模型集SelectedValue记录位于 ValueList 中的属性
  • 网格显示新的 SelectedValue但丢弃它,因为它被过滤掉了
  • 网格有 SelectedValue = 23 并且 View 模型有 SelectedValue = 42
  • 用户双击所选行(他看到 23)来编辑记录
  • ICommand映射到双击在 View 模型中调用
  • 查看模型启动编辑窗口,其中包含来自其 SelectedValue 的记录房产
  • 用户编辑记录 42 但认为是 23 .
  • 最佳答案

    我在很久以前的电子邮件中发现了这个解决方案,并认为我应该分享它(稍微清理一下)。这需要在当时调用 Telerik 和 Microsoft 的支持电话。
    基本上,我无法从 CoerceValueCallback 取消属性更新的原因是:

  • 在依赖属性
  • 的逻辑中强制值之前,绑定(bind)已更新
  • CoerceValueCallback 的这种行为是设计考虑的

  • 现在关于如何解决它的长答案:
    static GridView()
    {
    SelectedItemProperty.OverrideMetadata(typeof(GridView), new FrameworkPropertyMetadata(null, CoerceSelectedItemProperty));
    }

    // Rewriting SelectedItem coercion logic because of the following issue (we had support calls to both Telerik and Microsoft)
    // When
    // - a filter is applied on the grid
    // - user refreshes after modifying a record
    // - the record he has changed would be filtered out by the the grid filter
    // - the view model sets the SelectedItem to the modified record (which is hidden now)
    //
    // Telerik's coercion method resets the selected item to a visible row but because WPF's
    // binding occurs before the coercion method, the view model is not updated.
    // Even a call to UpdateSource() on the binding does not work in this case because the binding
    // is already updating the target while this happens so it does nothing when you call it.
    private static object CoerceSelectedItemProperty(DependencyObject d, object baseValue)
    {
    // Call normal Coercion method because we don't want to rewrite Telerik's logic
    // and keep result to return it at the end.
    object returnValue = SelectedItemProperty.GetMetadata(typeof(RadGridView)).CoerceValueCallback(d, baseValue);
    var control = (GridView)d;

    // If coerce returned something other than DependencyProperty.UnsetValue we can use it to push it back to
    // the binding source because it is of the right type and the right value.
    // The only case when we can use control.SelectedItem is when coerce returned UnsetValue otherwise the
    // view model is always one click late.
    object officialValue = returnValue == DependencyProperty.UnsetValue
    ? control.SelectedItem
    : returnValue;

    var binding = control.GetBindingExpression(SelectedItemProperty);
    var source = binding.ResolvedSource;
    var property = source.GetType().GetProperty(binding.ResolvedSourcePropertyName);
    property.SetValue(source, officialValue, null);
    return returnValue;
    }

    关于wpf - 在 DependencyProperty 的 CoerceValueCallback 中取消更新时如何更新绑定(bind)源?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13318622/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com