我正在尝试将某些功能嵌入我的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));
}
}
}
OnPropertyChanged
和InvokePropertyChanged
在应用程序的其他地方工作,只需处理围绕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做我想做的事?
编辑:
我对代码段进行了一些更改,使其与我最近进行这项工作的最新尝试保持一致
今天早上玩断点游戏,这是我建立的:
我还尝试了以下答案:https://stackoverflow.com/a/21851139/117651,其中ViewModel和XAML属性之间的绑定是在XAML中完成的。调用ViewModel中的getter,并且在调试器中运行时,PopulationId XAML属性在属性浏览器中显示期望值。但是,使用者和XAML属性之间的绑定不起作用,并且ViewModel中的值仍为0。
我也有PresentationTraceSources
连接到nlog,并且在日志中没有关于绑定表达式的抱怨。