简体   繁体   English

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

[英]Dependency Property Binding and updating to a custom control — It updates, but apparently not both ways?

ViewModel: 视图模型:

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

XAML: 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. 问题是虽然自定义控件中的DependencyProperty确实正确调整,但它不会更新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. 我意识到由于SomeAdjustedValue的命名,它似乎应该是CoerceValueCallback,但是Coercion也不会改变ViewModel值。 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. 我似乎无法更新我的ViewModel中的值,如果它是OnTextPropertyChanged回调开始的触发器......我做了一个调试跟踪,它没有通过新值再次通过ViewModel。 Not sure what to do here to fix this. 不知道该怎么做才能解决这个问题。

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. SetCurrentValue()方法确保保留绑定,其中如果使用Text属性设置器,在引擎盖下调用的简单SetValue()将删除任何绑定。

In the FrameworkPropertyMetadata, there are different constructors you can use. 在FrameworkPropertyMetadata中,您可以使用不同的构造函数。 Use one with the FrameworkPropertyMetadataOptions parameter. 使用FrameworkPropertyMetadataOptions参数。 The FrameworkPropertyMetadataOptions.BindsTwoWayByDefault option will turn on two way binding by default, otherwise it's just one way. FrameworkPropertyMetadataOptions.BindsTwoWayByDefault选项默认情况下将打开双向绑定,否则它只是一种方式。

Edit: So you did, I should stop trying to answer questions when I'm sick. 编辑:所以你做了,我生病时应该停止尝试回答问题。

A disclaimer first- this smells like logic that should live inside of the ViewModel, not in the UI binding. 首先是免责声明 - 这类似于逻辑应该存在于ViewModel内部,而不是在UI绑定中。

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

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. TextBox.Text是一个绑定,您将使用OnTextPropertyChanged的字符串值替换该绑定,因此该属性不再绑定到您的数据源。

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. 我认为您需要在TextBox.Text上获取绑定并更新源代码,但是我不建议这样做,因为您要将业务逻辑层与UI层混合。

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 如果要更改实际的数据源值,我会使用ViewModel的PropertyChanged事件来实现

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM