Вопросы по WPF MVVM

165
27 ноября 2018, 00:10

Во время освоения паттерна столкнулся с несколькими проблемами, которые опишу в данном вопросе. В своей программе из сторонних библиотек использую только Caliburn.Micro.

Вот код программы:

1) MainView.xaml

<Window x:Class="WpfMvvmTest5.Views.MainView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WpfMvvmTest5.Views"
    mc:Ignorable="d"
    Title="MainView" 
    Height="450" 
    Width="800">
<Grid ShowGridLines="True">
    <Grid.RowDefinitions>
        <RowDefinition Height="20"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="20"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="20"/>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="20"/>
    </Grid.ColumnDefinitions>
    <ListBox Grid.Row="1" Grid.Column="1" x:Name="ItemsListBox" SelectedItem="0" ItemsSource="{Binding Items}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Name}" />
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
    <TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding TextBlockText}" x:Name="TextBlock1"/>
    <ContentControl Grid.Row="3" Grid.Column="1" Content="{Binding ElementName=ItemsListBox, Path=SelectedItem.Content}" />
</Grid>

2) MainViewModel.cs

    using Caliburn.Micro;
    using System.Collections.Generic;
    using System.Windows;
    using WpfMvvmTest5.Models;
    using WpfMvvmTest5.Views;
    namespace WpfMvvmTest5.ViewModels
    {
        public class MainViewModel : Conductor<object>
        {
            private string _name;
            public string Name
            {
                get => _name;
                set
                {
                    _name = value;
                    NotifyOfPropertyChange(() => Name);
                }
            }
            private string _textBlockText;
            public string TextBlockText
            {
                get => _textBlockText;
                set
                {
                    _textBlockText = value;
                    NotifyOfPropertyChange(() => TextBlockText);
                }
            }
            public MainViewModel()
            {
                _textBlockText = "Test";
                Items.Add(new ItemsModel("Useless", null));
                Items.Add(new ItemsModel("TextChangerView", new TextChangerView()));
                Items.Add(new ItemsModel("TextChangerViewModel", new TextChangerViewModel()));
            }
            private List<ItemsModel> _items = new List<ItemsModel>();
            public List<ItemsModel> Items
            {
                get => _items;
                set => _items = value;
            }
            public void ChangeTextButton()
            {
                TextBlockText = "Text changed! Wow!";
                MessageBox.Show("This is MainVM!"); //TextChangerViewModel.ChangeTextButton();
            }
        }
    }

3) ItemsModel.cs

namespace WpfMvvmTest5.Models
{
    public class ItemsModel
    {
        public string Name { get; set; }
        public object Content { get; set; }
        public ItemsModel(string name, object content)
        {
            Name = name;
            Content = content;
        }
    }
}

4) TextChanger.xaml

<UserControl x:Class="WpfMvvmTest5.Views.TextChangerView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:cal="http://www.caliburnproject.org"
         xmlns:local="clr-namespace:WpfMvvmTest5.Views"
         mc:Ignorable="d" 
         d:DesignHeight="450" 
         d:DesignWidth="800">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <Button Grid.Row="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="Change da text" cal:Message.Attach="ChangeTextButton"/>
</Grid>

5) TextChangerViewModel.cs

using System.Windows;
namespace WpfMvvmTest5.ViewModels
{
    public class TextChangerViewModel
    {
        public static void ChangeTextButton() => MessageBox.Show("This is TextChangerVM!");
    }
}

6) Структура решения

В данный момент программа запускает ContentControl TextChangerView после выбора в ListBox соответствующего итема. Вопросы, собственно, следующие:

1) В UserControl'е содержится только кнопка, по клику на которую должно выводиться сообщение о том, что вызов метода произошел в TextChangerViewModel. На деле же вызывается аналогичный метод из родительского (в котором был создан UserControl) View. Если же попробовать в ListBox'е выбрать TextChangerViewModel, то в ContentControl'e не происходит вызов нужного UserControl. В этом и заключается первый вопрос - как в данном случае обратиться в ViewModel, а не View, чтобы впоследствии при нажатии на кнопку в данном ContentControl вызывалась функция из TextChangerViewModel?

2) В случае, если по клику на кнопку вызывается функция ChangeTextButton из TextChangerViewModel, возможно ли изменить текст TextBlock'а, находящегося в MainView? Если конкретнее, меня интересует ситуация, когда TextBlock - это заголовок, и он меняется при смене итема в ListBox. И вообще, стоит ли делать такое, или это какое-то грубое нарушение принципов MVVM?

3) Возможно ли обращаться к TextBlock из кода модели, и правильно ли это для использования MVVM? В своей программе на WinForms, когда у меня менялся этап выполнения задачи, я выделял жирным шрифтом текущий этап выполнения задачи, вопрос в том, как это сделать на WPF с использованием данного паттерна.

READ ALSO
yii2 как создать группы пользователей?

yii2 как создать группы пользователей?

Ситуация такая, нужно сделать так!

146
Получить данные из объекта

Получить данные из объекта

В Laravel, через $text = DB::table('articles')->select('text')->get(); получил переменную с результатом ` Object (

127
YII2 Валидаторы

YII2 Валидаторы

Не могу понять как работают валидаторы в YII, вот мне приходит пост запрос в контроллер:

233
Переопределить свойство объекта ActiveRecord

Переопределить свойство объекта ActiveRecord

Допустим, у меня есть 2 модели AR1

159