简体   繁体   English

WPF CustomControl无法绑定依赖项属性的两种方式查看模型

[英]WPF CustomControl unable to bind dependency property two way to view model

I have created a custom control with a dependency property bound to a view model property. 我已经创建了一个自定义控件,其依赖项属性绑定到了视图模型属性。

<wpf1:CustomTextBox StringProperty="{Binding StringValue}" />

The view model looks like this 视图模型如下所示

public class ViewModel : INotifyPropertyChanged
{
    public string StringValue
    {
        get { return m_stringValue; }
        set
        {
            m_stringValue = value;
            OnPropertyChanged("StringValue");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    private string m_stringValue;
}

The DataContext is set in the code behind DataContext是在后面的代码中设置的

public partial class MainWindow
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = ViewModel = new ViewModel();
    }

    public ViewModel ViewModel { get; set; }
}

The binding mode of the dependency property is two way by default 依赖项属性的绑定模式默认为两种方式

    public static readonly DependencyProperty StringPropertyProperty =
        DependencyProperty.Register(
            "StringProperty",
            typeof(string),
            typeof(CustomTextBox),
            new FrameworkPropertyMetadata
            {
                BindsTwoWayByDefault = true,
                DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
                PropertyChangedCallback = PropertyChangedCallback
            });

Now I have the problem, when the view model property StringValue is changed the custom control is notified but when I change the value of the dependency property the value of the view model is not changed. 现在,我遇到了问题,当更改视图模型属性StringValue时,将通知自定义控件,但是当我更改依赖项属性的值时,视图模型的值不会更改。

    private static void PropertyChangedCallback(DependencyObject dO,
    DependencyPropertyChangedEventArgs e)
    {
        var textBox = (CustomTextBox) dO;
        if (textBox.StringProperty == null)
            return;
        DoSomething(textBox.StringProperty)
        textBox.StringProperty = null;
    }

If I set the view model value to "some value" I want the custom control to use that string and reset it to null. 如果将视图模型值设置为“某个值”,则希望自定义控件使用该字符串并将其重置为null。 So far this works, but the view model value is not synchronized and remains "some value" instead of null. 到目前为止,这是可行的,但是视图模型值尚未同步,而是保持“某些值”而不是null。 Any ideas how to do this? 任何想法如何做到这一点? And why the two way binding does not work that way? 为什么双向绑定不能那样工作?

Thanks. 谢谢。

this line 这条线

textBox.StringProperty = null;

removes binding which was defined earlier ( <wpf1:CustomTextBox StringProperty="{Binding StringValue}" /> ) 删除先前定义的绑定( <wpf1:CustomTextBox StringProperty="{Binding StringValue}" />

try use 尝试使用

textBox.SetCurrentValue(StringPropertyProperty, null);

The reason for why you code does not work as expected is that you're assigning new value to your StringProperty while still handling the previous change to that property. 您的代码无法按预期工作的原因是,您在为StringProperty分配新值的同时仍在处理对该属性的先前更改。 I don't really know the mechanics behind that (possibly it's some kind of mechanism meant to prevent potentially infinite recursive calls?), but I am 100% that that is the culprit. 我真的不了解其背后的机制(可能是某种旨在防止潜在的无限递归调用的机制?),但我100%认为是罪魁祸首。

To solve your problem it is sufficient to defer new value assignment until the control is returned from your handler, which can be easily achieved by using the Dispatcher associated with your control: 为了解决您的问题,将新的值分配推迟到从处理程序返回控件之前就足够了,这可以通过使用与控件关联的Dispatcher轻松实现:

private static void PropertyChangedCallback(DependencyObject dO,
    DependencyPropertyChangedEventArgs e)
{
    var textBox = (CustomTextBox) dO;
    if (textBox.StringProperty == null)
        return;
    DoSomething(textBox.StringProperty)
    //following lambda will be queued for execution rather than executed immediately
    //and is guaranteed to be executed after this handler has finished
    textBox.Dispatcher.InvokeAsync(() => textBox.StringProperty = null);
}

If you're using .NET version prior to 4.5 you will need to use Dispatcher.BeginInvoke method instead. 如果您使用的是4.5之前的.NET版本,则需要改用Dispatcher.BeginInvoke方法。

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

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