Как сделать привязку caliburn.micro модели представления к выбранному значению combobox?

Я относительно низкий на кривой как для WPF, так и для Caliburn.Micro.

Моя цель здесь - переместить привязку выделенного элемента combobox из кода ShellView позади в View Model, так же, как и для коллекции элементов combobox.

XAML:

<Window x:Class="EomDatabaseUtility.Views.ShellView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Eom Tool Database Utility" Height="350" Width="525">
    <Grid>
        <DataGrid AutoGenerateColumns="False" Height="258" HorizontalAlignment="Left" Margin="12,41,0,0" Name="dataGrid1" VerticalAlignment="Top" Width="479" />
        <Button Content="Execute" Height="23" HorizontalAlignment="Left" Margin="416,12,0,0" VerticalAlignment="Top" Width="75" x:Name="Execute" />
        <ComboBox Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" VerticalAlignment="Top" Width="120" x:Name="CatalogName" SelectedValuePath="{Binding Path=SelectedCatalogName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
    </Grid>
</Window>

Code Behind (где цель состоит в том, чтобы не добавлять код, если я правильно понимаю):

namespace EomDatabaseUtility.Views
{
    using System.Windows;

    public partial class ShellView : Window
    {
        public ShellView()
        {
            InitializeComponent();
        }

        // --> This should go in the view model, Right?
        private string selectedCatalogName;
        public string SelectedCatalogName
        {
            get { return selectedCatalogName; }
            set { selectedCatalogName = value; }
        }
    }
}

View Model (в настоящее время поставляется коллекция элементов в combobox, а также обработчик событий кнопки):

namespace EomDatabaseUtility.ViewModels
{
    using Caliburn.Micro;
    using System.Collections.Generic;

    public class ShellViewModel : PropertyChangedBase
    {
        public List<string> CatalogName
        {
            get
            {
                return new List<string> { "foo", "bar" };
            }
        }

        public void Execute()
        {
            System.Windows.MessageBox.Show("hello");
        }
    }
}

Ответ 1

Вы можете привязать SelectedItem из ComboBox к свойству в вашей модели представления:

<ComboBox x:Name="CatalogName" ... SelectedItem="{Binding SelectedCatalog}" />

public class ShellViewModel : PropertyChangedBase
{
    private string selectedCatalog;

    public List<string> CatalogName
    {
        get
        {
            return new List<string> { "foo", "bar" };
        }
    }

    public string SelectedCatalog
    {
       get
       {
          return this.selectedCatalog;
       }

       set
       {
          this.selectedCatalog = value;
          this.NotifyOfPropertyChange(() => this.SelectedCatalog);
       }
    }

Фактически, поскольку ваш ComboBox имеет имя CatalogName, соглашения Caliburn.Micro будут искать свойство SelectedCatalogName (или ActiveCatalogName) и автоматически связывать ComboBox SelectedItem с этим, поэтому вы можете использовать:

<ComboBox x:Name="CatalogName" ... />

public string SelectedCatalogName
{
  ...
}

Несколько замечаний:

  • Мы вызываем NotifyOfPropertyChange() в установщике для SelectedCatalog. Это уведомляет пользовательский интерфейс, что значение изменилось всякий раз, когда мы устанавливаем его из модели представления, чтобы пользовательский интерфейс обновлялся. Этот метод является частью PropertyChangedBase.
  • Вы действительно должны использовать тип коллекции, который поддерживает сбор измененных уведомлений в ваших моделях просмотра, таких как ObservableCollection который поставляется с WPF, или Caliburn.Micro BindableCollection (который реализует Caliburn.Micro IObservableCollection). Это позволяет уведомлять пользовательский интерфейс, когда объекты добавляются/удаляются из ваших коллекций из модели представления.
  • Вероятно, ваша модель представления оболочки должна использовать тип Screen или Conductor (а не PropertyChangedBase), если он будет иметь жизненный цикл (активация/деактивация и т.д.) Или будет иметь текущий активный элемент (экран), который может измениться во время выполнения.