WPF数据绑定到具有ViewModel的UserControl上的属性

时间:2018-10-21 16:32:22

标签: c# wpf xaml mvvm

我正在尝试将某些功能嵌入我的MVVM样式应用程序中的可重用UserControl中。到目前为止,MVVM框架大多是手工编写的,因为WPF应用程序开始时的生活基本上就是WinForms应用程序。

我正在创建的UserControl只是UI中的ComboBox,其中一些数据加载是由ViewModel完成的。应用程序中的所有ViewModels都是由ViewModel定位器加载的,因此我不需要将ViewModels注入ViewModels,这在应用程序中的其他任何地方都可以使用,因此在这里我认为这不是问题:

<UserControl DataContext="{Binding Common_PopulationSelector,Source={StaticResource ViewModelLocator}}">
    <ComboBox ItemsSource="{Binding Population}" SelectedItem="{Binding SelectedPopulation}" DisplayMemberPath="PopulationName" IsEditable="False"></ComboBox>
</UserControl>

ViewModel的相关位:

public class PopulationSelectorViewModel : BaseViewModel
{
    public override async void OnCreate()
    {
        //Called by the ViewModelLocator when this isntance is created
        //Data loading done here, puts a list of Populations into the Populations collection
        //SelectedPopulation gets set to a default value here
    }

    public ObservableCollection<Population> Populations { get; }

    private Population _selectedPopulation;
    public Population SelectedPopulation
    {
        get => _selectedPopulation;
        set
        {
            OnPropertyChanged(ref _selectedPopulation, value);
            InvokePropertyChanged(nameof(PopulationId));
        }
    }

     public int PopulationId
     {
        get => _selectedPopulation?.PopulationID ?? 0;
        set
        {
            SelectedPopulation= Populations.FirstOrDefault(r => r.PopulationID == value) ?? _selectedPopulation;
            InvokePropertyChanged(nameof(PopulationId));
        }
    }
}

OnPropertyChangedInvokePropertyChanged在应用程序的其他地方工作,只需处理围绕INotifyPropertyChanged的管道

这些位正常工作,数据被加载,SelectedPopulation更改,并且带有PopulationId属性。

问题出在哪里是将“人口识别”暴露为UserControl使用者可以绑定的XAML属性。像这样消耗该控件:

<views:PopulationSelector PopulationId="{Binding Path=DataContext.PopulationId, RelativeSource={RelativeSource AncestorType={x:Type local:SearchParameters}}, Mode=TwoWay}" />

SearchParameters是包含选择器的UserControl。为了公开人口编号,我在XAML代码的后面有这个

public partial class PopulationSelector : UserControl
{
    public PopulationSelector()
    {
        InitializeComponent();
        this.SetBinding(PopulationIdProperty, new Binding("PopulationId") { Mode = BindingMode.TwoWay });
    }

    public static readonly DependencyProperty PopulationIdProperty = DependencyProperty.Register(
        "PopulationId", typeof(int), typeof(PopulationSelector), new PropertyMetadata(-1));

    public int PopulationId
    {
        get
        {

            return (int)GetValue(PopulationIdProperty);
        }
        set
        {
            var oldValue = (int)GetValue(PopulationIdProperty);
            if (oldValue != value) SetValue(PopulationIdProperty, value);
        }
    }
}

这显然是发生中断的地方。我在这里将DependencyProperty的默认值设置为-1,并且它的确更改为0,因此使用消耗它的UserControl进行绑定似乎有效。但是PopulationId WPF属性似乎从未从ViewModel更新。

因此,简而言之(这很长时间了,因为我在撰写本文时尝试掩盖真相):我试图将用户控件上的WPF属性绑定到该控件的ViewModel上。绑定到用户控件本身似乎有效,但从视图模型到用户控件的绑定无效。我怎样才能让WPF做我想做的事?

编辑:

我对代码段进行了一些更改,使其与我最近进行这项工作的最新尝试保持一致

  • 已更新了用户控件代码背后的设置器,以匹配我使用的引用,即:Twoway-bind view's DependencyProperty to viewmodel's property?
  • 更新了XAML属性和ViewModel之间的绑定。发布此代码时,我稍微简化了代码(在我绑定到SelectedPopulation的属性之前),发布的代码无法正常工作。我在视图模型上为“人口ID”添加了一个二传手,所以两种方式的绑定都可以正常工作

今天早上玩断点游戏,这是我建立的:

  • 正在调用ViewModel中SelectedPopulation的设置方法,因此ComboBox和ViewModel之间的绑定很好。
  • 从不调用ViewModel中人口ID的吸气剂
  • 在后面的UserControl代码中,PopulationId的获取器或设置器永远不会被调用
  • 从不调用使用此用户控件的视图中的“人口ID”的设置器。

我还尝试了以下答案:https://stackoverflow.com/a/21851139/117651,其中ViewModel和XAML属性之间的绑定是在XAML中完成的。调用ViewModel中的getter,并且在调试器中运行时,PopulationId XAML属性在属性浏览器中显示期望值。但是,使用者和XAML属性之间的绑定不起作用,并且ViewModel中的值仍为0。

我也有PresentationTraceSources连接到nlog,并且在日志中没有关于绑定表达式的抱怨。

0 个答案:

没有答案