Binding dependency 属性 - 在自定义用户控件中设置,在viewmodel中获取

Binding dependency property - set in custom user control, get in viewmodel

目的是在自定义 UserControl 中实例化一个对象,然后从视图模型访问该实例。但是以下内容不起作用,视图模型中的 UpRatings 属性 为空。

具有依赖性的自定义 UserControl 属性

public partial class Scale:UserControl
{

    public Scale()
    {
        InitializeComponent();
    }

    public static readonly DependencyProperty MouseRatingsProperty = 
        DependencyProperty.Register(
        "MouseRatings",
        typeof(IObservable<double>),
        typeof(Scale));

    public IObservable<double> MouseRatings
    {
        get
        {
            return (IObservable<double>)GetValue(MouseRatingsProperty);
        }
        set
        {
            SetValue(MouseRatingsProperty, value);                
        }
    }

    // requires System.Reactive NuGet
    private ISubject<double> _mouseRatings = new Subject<double>();

    protected override void OnInitialized(EventArgs e)
    {
        base.OnInitialized(e);
        // _mouseRatings is the object instance I need to access in the viewmodel
        MouseRatings = _mouseRatings;
    }
}

查看

<StackPanel>
    <scale:Scale MouseRatings="{Binding Path=UpRatings, Mode=TwoWay}"/>
</StackPanel>

视图模型

// requires Prism.Wpf NuGet
public class MyViewModel : BindableBase
{
    public IObservable<double> UpRatings { get; set; }

    // called after the DataContext is set, so the UpRatings binding should work here by now
    // see https://github.com/PrismLibrary/Prism/blob/master/Documentation/WPF/60-Navigation.md
    public void OnNavigatedTo(NavigationContext navigationContext)
    {
        // but UpRatings is unfortunately null here
        Trace.WriteLine(UpRatings == null ? "null" : "not null");
    }

}

请注意,DataContext 不是直接在自定义用户控件上设置的,而是她的父控件(我可以在自定义用户控件中确认这一点)。

MouseRatings = _mouseRatings 时开始生效;稍后调用如下,而如果将 MouseRatings 设置为 OnInitialized,则由于某种神秘原因会丢失其值。

public Scale()
    {
        InitializeComponent();
        IsVisibleChanged += Scale_IsVisibleChanged;
    }

private void Scale_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        if (IsVisible)
        {
            MouseRatings = _mouseRatings;
        }
    }

它也可以在 UserControl Loaded 事件中设置它,但是 viewmodel 必须等待额外的时间才能访问该对象。