【问题标题】:Dependency Property Binding and updating to a custom control -- It updates, but apparently not both ways?依赖属性绑定和更新到自定义控件——它更新,但显然不是双向的?
【发布时间】:2012-02-03 10:52:51
【问题描述】:

视图模型:

public class MyViewModel : INotifyPropertyChanged
{
    public string MyText { ... }
}

XAML:

<my:MySpecialTextBox Text="{Binding MyText}" />

自定义控件:

public class MySpecialTextBox : TextBox
{
    static MySpecialTextBox()
    {
        TextProperty.OverrideMetadata(typeof(MySpecialTextBox),
            new FrameworkPropertyMetadata
            {
                BindsTwoWayByDefault = true,
                DefaultValue = string.empty,
                PropertyChangedCallback = OnTextPropertyChanged
            });
    }

    private static void OnTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var control = d as MySpecialTextBox;

        if (control != null)
        {
            control.Text = SomeAdjustedValue((string)e.NewValue);
        }
    }
}

问题在于,虽然自定义控件中的 DependencyProperty 可以正确调整,但它不会更新 ViewModel。我意识到由于 SomeAdjustedValue 的命名,这个似乎应该是 CoerceValueCallback,但 Coercion 也不会更改 ViewModel 值。如果它是 OnTextPropertyChanged 回调的触发器,我似乎无法更新我的 ViewModel 中的值......我做了一个调试跟踪,它没有第二次使用新值通过 ViewModel。不知道该怎么做才能解决这个问题。

【问题讨论】:

  • 只是为了确保我理解-您期望 ViewModel 发生更改,通过 PropertyChanged 通知提升到 UI,以更新 UI,然后由于绑定回调,随后被路由回到 ViewModel?

标签: c# wpf data-binding mvvm dependency-properties


【解决方案1】:

在 FrameworkPropertyMetadata 中,您可以使用不同的构造函数。使用一个与 FrameworkPropertyMetadataOptions 参数。 FrameworkPropertyMetadataOptions.BindsTwoWayByDefault 选项会默认开启双向绑定,否则只有一种方式。

编辑:原来如此,我生病时应该停止回答问题。

【讨论】:

  • 嗯,我确实将 BindsTwoWayByDefault 设置为 true。
【解决方案2】:

首先声明一个免责声明——这听起来像是应该存在于 ViewModel 内部而不是 UI 绑定中的逻辑。

也就是说,如果您打算这样做,我认为您需要首先检查“调整后的值”是否与已经提供的不同(以避免无限循环),然后使用DependencyProperty.SetValue在控件上设置依赖属性的值,而不是仅仅设置它的 Text 属性。

【讨论】:

  • 这也不起作用...它再次在我的自定义控件上设置值,但它不会更新视图模型。
  • SetValue() 替换绑定;请改用 SetCurrentValue()。
【解决方案3】:

TextBox.Text 是一个绑定,您将用OnTextPropertyChanged 中的字符串值替换该绑定,因此该属性不再绑定到您的数据源。

我认为您需要在 TextBox.Text 上进行绑定并更新源代码,但我不建议您这样做,因为您会将业务逻辑层与 UI 层混合在一起。

如果您只想显示一些自定义格式,我会在转换器中执行此操作,因此它实际上不会更改您的数据源的值。如果您想更改实际的数据源值,我会使用 ViewModel 的 PropertyChanged 事件来做到这一点

【讨论】:

  • 在下面查看我的答案 - 现在使用 .NET 4 可以调用 SetCurrentValue(dp, value) 并设置值而不影响绑定。
【解决方案4】:

你试过了吗?

private static void OnTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var control = d as MySpecialTextBox;

    if (control != null)
    {
        control.SetCurrentValue(TextBox.TextProperty, SomeAdjustedValue((string)e.NewValue));
    }
}

SetCurrentValue() 方法可确保保留绑定,如果使用 Text 属性设置器,则在后台调用的简单 SetValue() 将删除任何绑定。

【讨论】:

  • 请注意,您可能还需要设置一些成员布尔标志,例如调用 SetCurrentValue() 时出现“ignoreTextPropertyChangedEvent”;否则你可能会陷入无限循环。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-06
  • 1970-01-01
  • 1970-01-01
  • 2012-08-29
  • 2011-12-18
  • 2019-05-26
  • 2011-03-05
相关资源
最近更新 更多