Я пытаюсь встроить некоторую функциональность в повторно используемый UserControl в моем приложении в стиле MVVM.Фреймворк MVVM на этом этапе в большинстве случаев выполняется вручную, поскольку приложение WPF начало свою жизнь, будучи написанным в основном как приложение WinForms.
Созданный мной UserControl - это просто ComboBox
в пользовательском интерфейсе с некоторыми данными.загрузка выполнена ViewModel.Все ViewModel в приложении загружаются локатором 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.
Суть проблемы заключается в представлении PopulationId как свойства XAML, с которым могут связываться потребители UserControl.Этот элемент управления используется следующим образом:
<views:PopulationSelector PopulationId="{Binding Path=DataContext.PopulationId, RelativeSource={RelativeSource AncestorType={x:Type local:SearchParameters}}, Mode=TwoWay}" />
SearchParameters - это UserControl, содержащий селектор.Чтобы выставить PopulationId, у меня есть это в коде 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 делать то, что я хочу?
Редактировать:
Я внес несколько изменений в мои фрагменты кода, которые приводят его в соответствие с моимнедавние попытки сделать эту работу
- Обновлен сеттер в codebehind для usercontrol, чтобы он соответствовал ссылке, которую я использовал, а именно: DependencyProperty представления Twoway-bind для свойства viewmodel?
- Обновлена привязка между свойством XAML и ViewModel.При публикации я немного упростил код (до привязки к свойству вне SelectedPopulation), и опубликованный код не работал.Я добавил сеттер в PopulationId для модели представления, чтобы двусторонняя привязка работала правильно
Сегодня утром немного поиграв с точками останова, вот что я установил:
- Вызывается установщик для SelectedPopulation в ViewModel, поэтому связывание между ComboBox и ViewModel в порядке.
- Получатель для PopulationId в ViewModel никогда не вызывается
- Получатель или установщик дляPopulationId в коде UserControl никогда не вызывается
- Установщик для PopulationId в представлении, использующем этот пользовательский элемент управления, никогда не вызывается
Я также только что попробовал этот ответ: https://stackoverflow.com/a/21851139/117651 где привязка между ViewModel и свойством XAML выполняется в XAML.Вызывается метод получения в ViewModel, а свойство PopulationId XAML показывает ожидаемое значение в проводнике свойств при работе в отладчике.Однако привязка между потребителем и свойством XAML не работает, и значение в ViewModel остается равным 0.
У меня также есть PresentationTraceSources
, подключенное к nlog, и в журналах нет жалобС уважением к обязательным выражениям.