依赖属性绑定和更新到自定义控件——它更新,但显然不是两种方式?

发布于 2024-12-24 19:27:52 字数 1190 浏览 6 评论 0原文

ViewModel:

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:

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

XAML:

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

Custom Control:

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);
        }
    }
}

The problem is that while the DependencyProperty in the custom control does adjust properly, it does not update the ViewModel. I realize that this seems as if it should be a CoerceValueCallback due to the naming of SomeAdjustedValue, but Coercion does not change the ViewModel value either. I can't seem to update the value in my ViewModel if it was the trigger for the OnTextPropertyChanged callback to begin with... I did a debug trace and it does not go through the ViewModel a second time with the new value. Not sure what to do here to fix this.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

此刻的回忆 2024-12-31 19:27:52

在 FrameworkPropertyMetadata 中,您可以使用不同的构造函数。将其与 FrameworkPropertyMetadataOptions 参数一起使用。 FrameworkPropertyMetadataOptions.BindsTwoWayByDefault 选项默认情况下将打开两种方式绑定,否则它只是一种方式。

编辑:所以你做到了,当我生病时我应该停止尝试回答问题。

In the FrameworkPropertyMetadata, there are different constructors you can use. Use one with the FrameworkPropertyMetadataOptions parameter. The FrameworkPropertyMetadataOptions.BindsTwoWayByDefault option will turn on two way binding by default, otherwise it's just one way.

Edit: So you did, I should stop trying to answer questions when I'm sick.

最笨的告白 2024-12-31 19:27:52

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

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

A disclaimer first- this smells like logic that should live inside of the ViewModel, not in the UI binding.

That said, if you are set on doing it this way, I think that you need to first check whether the "Adjusted Value" is different than the one already provided (to avoid looping indefinitely), then use DependencyProperty.SetValue to set the value of the dependency property on the control, rather than just setting it's Text property.

前事休说 2024-12-31 19:27:52

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

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

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

TextBox.Text is a binding, and you are replacing that binding with a string value in OnTextPropertyChanged, so the property is no longer bound to your datasource.

I think you would need to get the binding on TextBox.Text and update the source, however I wouldn't recommend doing that since you'd be mixing your Business Logic layer with your UI layer.

If you only want a display some custom formatting, I would do it in a Converter so it doesn't actually change your data source's value. If you want to change the actual data source value, I would do that with the ViewModel's PropertyChanged event

£冰雨忧蓝° 2024-12-31 19:27:52

你尝试过这个吗?

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() 将删除任何绑定。

Did you try this?

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

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

The SetCurrentValue() method ensures that the binding is preserved, where a simple SetValue() which is what is called under the hood if you use the Text property setter will remove any binding.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文