Обратиться из UserControl к MainWindow MVVM

109
16 сентября 2019, 05:30

Подскажите, вот у меня есть UserControl на нем listBox, при нажатии на Item необходимо помещать Page во Frame Content главной формы (MainWindow). Как такое можно провернуть?

Answer 1

Как вариант решения данной задачи:

Создание UserControl:

Я создам простой UserControl, который будет содержать в себе ListBox и наружу он будет отдавать такие свойства как ItemsSource и SelectedItem.

  • Создадим два DependencyProperty в коде UserControl'a:

    public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register(
        "ItemsSource", typeof(IEnumerable), typeof(MenuControl), new PropertyMetadata(default(IEnumerable)));
    public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register(
        "SelectedItem", typeof(object), typeof(MenuControl), new PropertyMetadata(default(object)));
    public IEnumerable ItemsSource
    {
        get => (IEnumerable)GetValue(ItemsSourceProperty);
        set => SetValue(ItemsSourceProperty, value);
    }
    public object SelectedItem
    {
        get => GetValue(SelectedItemProperty);
        set => SetValue(SelectedItemProperty, value);
    }
  • Теперь привяжем в XAML все это:

    • Задаем имя для UserControl, прописав x:Name="Control".
    • Создаем и привязываем ListBox:

      <ListBox ItemsSource="{Binding ElementName=Control, Path=ItemsSource}" 
               SelectedItem="{Binding ElementName=Control, Path=SelectedItem}"/>

Создадим базовый класс для VM страниц:

Заодно сделаем здесь реализацию INotifyPropertyChanged.

class BaseVM : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public void RaisePropertyChanged([CallerMemberName] String propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

ViewModel для одного итема в меню:

Нам надо что бы каждый объект в ListBox имел имя и VM нужной страницы.

  • Создаем класс MenuItemViewModel
  • Прописываем все свойства:

    public string Name { get; set; }
    public BaseVM ViewModel { get; set; }
  • Перепишем ToString для того, что бы не городить стили. Если у вас объект более сложный, то лучше перепишите стиль ListBox!

    public override string ToString() => Name;
  • Ну и для удобства сделаем конструктор:

    public MenuItemViewModel(string name, BaseVM viewModel)
    {
        Name = name;
        ViewModel = viewModel;
    }

Создаем новую страницу со своей VM:

  • Добавляем новый UserControl и называем его например FirstPage.
  • В XAML для теста напишем по центру текст, взятый из VM и сделаем его другого цвета:

    <TextBlock Foreground="Red" Text="{Binding Text}" FontSize="20"
               VerticalAlignment="Center" HorizontalAlignment="Center"/>
  • Далее создаем VM класс, назовем его FirstPageViewModel, сразу наследуем от BaseVM.

  • В данной VM пропишем всего одно свойства с текстом:

    class FirstPageViewModel : BaseVM
    {
        public FirstPageViewModel()
        {
            Text = "Первая страница";
        }
        private string text;
        public string Text
        {
            get => text;
            set
            {
                text = value;
                RaisePropertyChanged();
            }
        }
    }
  • Делаем также и другие страницы, со своими свойствами и разметкой.

Работаем с главной ViewModel:

Здесь мы все объединим в одно целое.

  • Создаем класс MainViewModel.
  • Наследуем класс от ранее созданного BaseVM.
  • Создаем коллекцию наших меню:

    public ObservableCollection<MenuItemViewModel> MenuItems { get; set; }
  • Создаем свойства текущей страницы и выбранного объекта меню (везде реализуем INPC):

    private BaseVM currentContent;
    public BaseVM CurrentContent
    {
        get => currentContent;
        set
        {
            currentContent = value;
            RaisePropertyChanged();
        }
    }
    private MenuItemViewModel selectedMenu;
    public MenuItemViewModel SelectedMenu
    {
        get => selectedMenu;
        set
        {
            selectedMenu = value;
            CurrentContent = value.ViewModel;
            RaisePropertyChanged();
        }
    }
  • MainViewModel задаем как DataContext текущего окна.

Прорабатываем стиль главного окна:

<Window.Resources>
    <DataTemplate DataType="{x:Type vm:FirstPageViewModel}">
        <сt:FirstPage/>
    </DataTemplate>
    <DataTemplate DataType="{x:Type vm:SecondPageViewModel}">
        <сt:SecondPage/>
    </DataTemplate>
</Window.Resources>
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition Width="3*"/>
    </Grid.ColumnDefinitions>
    <сt:MenuControl ItemsSource="{Binding MenuItems}" SelectedItem="{Binding SelectedMenu, Mode=TwoWay}"/>
    <ContentPresenter Grid.Column="1" Content="{Binding CurrentContent, Mode=TwoWay}"/>
</Grid>

Заполняем список страниц:

Тут достаточно в конструкторе MainViewModel прописать инициализацию коллекции.

public MainViewModel()
{
    MenuItems = new ObservableCollection<MenuItemViewModel>()
    {
        new MenuItemViewModel("Страница 1", new FirstPageViewModel()),
        new MenuItemViewModel("Страница 2", new SecondPageViewModel())
    };
}

Результат:

Вот вроде и все, запускаем и любуемся результатом.

Таким довольно простым способом мы связали UserControl с меню и сделали изменение страницы в главном окне.

READ ALSO
Unity, проверка наличия компонента в Editor

Unity, проверка наличия компонента в Editor

Недавно решил поиграть с кастомным Unity Editor

124
как добавить дату и время к строке

как добавить дату и время к строке

Подскажите, как можно с помощью php пересохранить файл с указанием даты и текущего времени?

187
php реферальная система

php реферальная система

Пишу многоуровневую реферальную систему с рангамиТ

121
Yii2 file kit не правильно проставляет индексы

Yii2 file kit не правильно проставляет индексы

Суть вот в чём: Загружаю файлы через https://githubcom/yii2-starter-kit/yii2-file-kit На выходе получается так, что грузит все файлы, но я не могу их сохранить так...

116