Ronald Janssen Ответов: 2

Mvvm - model class - каков "наилучший" способ доступа к закрытым членам и свойствам внутри класса?


Всем Привет!!

Первый вопрос здесь, так что полегче со мной, люди! ;-) Кроме того, имейте в виду, что я новичок с VS и VB, использую его уже полгода. Простите меня, если я использую неправильные термины, все еще очень новые для этого.

Ситуация:
Я разрабатываю vb.net настольное приложение в VS2017 с использованием шаблона MVVM. Все еще многому учусь, но добиваюсь хорошего прогресса, поэтому читаю здесь много статей!

До сих пор у меня есть свой уровень пользовательского интерфейса (комбинация окон, пользовательских элементов управления и интерфейсов), режимы просмотра и модели данных. Все еще нужно сделать уровень доступа к данным (или реализовать это в модели данных, пока не уверен).

Общая проблема:
Один аспект, который мне трудно "понять", - это когда использовать частное поле против свойства этого частного поля внутри сам класс. Воспользовался поиском, но не нашел подходящих ответов. Является ли наилучшим подходом использование членов свойства только для привязки или нет никакого "общего правила"?

Пример:
Класс модели Person имеет по умолчанию Ctor New() и реализует INotifyPropertyChanged и INotifyDataErrorInfo (через базовый класс). Я использую Ctor по умолчанию, потому что мне нужны данные времени разработки.
В Новой() я поставил перед членами собственность (номер и название), а не отдельным членам (_number и _name). Таким образом, события запускаются. При создании экземпляра класса Person в моей виртуальной машине и использовании Привязок в моем пользовательском элементе управления (и некоторых материалах XAML) Я получаю хорошие подсказки с сообщениями об ошибках при отображении окна/uc (выбор дизайна). Кнопки (привязка с командами ретрансляции) устанавливаются и обновляются. До сих пор это работает идеально, и программирование его "чувствует" себя хорошо.

Конкретная проблема:
Но затем, когда я загружаю список (функция Shared GetList() в классе модели), события запускаются для каждой новой записи при использовании Ctor по умолчанию (и если я устанавливаю свойства в GetList (), они даже запускаются во второй раз). Поэтому для загрузки списка я создал второй Ctor New (), который устанавливает закрытые члены. Потому что мне кажется "неправильным", что все эти события запускаются, когда они мне не нужны.

Это нормально делать? Использовать один конструктор для "инициализацию" и один конструктор для "загрузки". Или мне следует изменить способ использования закрытых членов и свойств?

Также не стесняйтесь публиковать свои мысли о "моей" реализации MVVM. Я не собираюсь использовать пуристский подход MVVM, я единственный разработчик, и так оно и останется. Но есть ли серьезные недостатки в том подходе, который я использую, или есть лучший подход? (Или я должен сделать новый вопрос для этого?)

(Когда я публиковал это, я не видел раздела для выбора, надеюсь, что он окажется в нужном месте)

Что я уже пробовал:

Создать конструктор по умолчанию и установить свойства
Создать второй конструктор и установить приватные поля

2 Ответов

Рейтинг:
2

GKP1992

Общая идея наличия свойства для доступа к закрытому полю класса состоит в том, чтобы иметь возможность установить его вне этого класса, и поэтому свойства имеют модификатор доступа "Public".
Нет смысла использовать свойство для доступа к частной переменной внутри класса. Просто используйте переменную. Кроме того, вам также не нужно вызывать конструктор. Если вы используете двустороннюю привязку, то при обновлении свойства оно автоматически будет отражено в представлении. В этом и заключается красота модели MVVM.
Все, что вам нужно сделать, это "уведомить" представление о том, что свойство было обновлено.


Ronald Janssen

Привет GKP1992 thx за реакцию. Большую часть я понимаю. Но когда я получаю список людей, я должен вызвать конструктор для каждой записи, не так ли?

Пример:
Публичная Общая Функция Getlist() Как BindingList(Of PersonModel)
Тусклый результат как новый список Привязок(PersonModel)
для x = от 1 до 5
Тусклый человек как новый Человекмодальный()
person.number = x (или, как вы предлагаете -> person._number = x)
person.name = "имя" & Cstr(x)
результат.Добавить(персона)
следующий
Конечная Функция

GKP1992

Да, вам нужно будет вызывать конструктор для каждого человека, поскольку вы каждый раз создаете нового человека. Я неправильно это понял, прошу прощения. Да, для PersonModel создается конструктор, который устанавливает закрытые члены для каждого человека в GetList. Добавьте их в результат и уведомите представление об изменении свойства "список лиц", к которому привязан список.

Рейтинг:
2

Graeme_Grant

Цитата:
Model–View–ViewModel (MVVM) - это архитектурный шаблон программного обеспечения.

MVVM facilitates a separation of development of the graphical user interface – be it via a markup language or GUI code – from development of the business logic or back-end logic (the data model). The view model of MVVM is a value converter,[1] meaning the view model is responsible for exposing (converting) the data objects from the model in such a way that objects are easily managed and presented. In this respect, the view model is more model than view, and handles most if not all of the view's display logic.[1] The view model may implement a mediator pattern, organizing access to the back-end logic around the set of use cases supported by the view.
ссылка: Модель–Вид–viewmodel - Википедия[^]

WPF делает это возможным с помощью привязка данных[^].

Я являюсь независимым разработчиком программного обеспечения, и я нахожу шаблон MVVM, наряду с MEF, очень полезным шаблоном для соблюдения.

Однако похоже, что вы не хотите использовать шаблон MVVM, а хотите использовать систему привязки данных. Это тоже прекрасно. Вот пример использования привязки данных без шаблона MVVM:

страница XAML:
<Window x:Class="WpfSimpleBinding.MainWindow"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"



        mc:Ignorable="d"

        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"



        xmlns:local="clr-namespace:WpfSimpleBinding"



        Title="Basic code-behin binding example"

        WindowStartupLocation="CenterScreen" Height="400" Width="300">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <Grid.Resources>
            <DataTemplate DataType="{x:Type local:PersonModel}">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition/>
                        <ColumnDefinition Width="Auto"/>
                    </Grid.ColumnDefinitions>
                    <TextBlock Text="{Binding Name}" Margin="10 3"/>
                    <TextBlock Text="{Binding Age}" Margin="10 3"

                               Grid.Column="1"/>
                </Grid>
            </DataTemplate>
        </Grid.Resources>

        <ListBox ItemsSource="{Binding Persons}">
            <ListBox.ItemContainerStyle>
                <Style TargetType="ListBoxItem">
                    <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
                </Style>
            </ListBox.ItemContainerStyle>
        </ListBox>
        <Button Content="Randomize" Padding="10 5" Margin="10"

                HorizontalAlignment="Center" VerticalAlignment="Center"

                Grid.Row="1" Click="Button_Click"/>
    </Grid>

</Window>

Основа INotifyPropertyChanged реализация (многоразовая):
public abstract class ObservableBase : INotifyPropertyChanged
{
    public void Set<TValue>(ref TValue field, TValue newValue, [CallerMemberName] string propertyName = "")
    {
        if (EqualityComparer<TValue>.Default.Equals(field, default(TValue)) || !field.Equals(newValue))
        {
            field = newValue;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

модель данных:
public class PersonModel : ObservableBase
{
    private string name;
    public string Name
    {
        get { return name; }
        set { Set(ref name, value); }
    }

    private int age;
    public int Age
    {
        get { return age; }
        set { Set(ref age, value); }
    }
}

а также код для страницы XAML:
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;
        Mock();
    }

    public ObservableCollection<PersonModel> Persons { get; set; }
        = new ObservableCollection<PersonModel>();

    private Random rand = new Random();

    private void Mock()
    {
        for (int i = 0; i < 10; i++)
        {
            Persons.Add(new PersonModel
            {
                Name = string.Format("Person {0}", i),
                Age = rand.Next(20, 50)
            });
        }
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        foreach (var person in Persons)
        {
            person.Age = rand.Next(20, 50);
        }
    }
}

Мы используем традиционные (стиль winform) управляющие события с привязкой данных WPF. Недостатком этого, который разрешает шаблон MVVM, является то, что код позади (ViewModel) тесно связан со страницей XAML и элементами управления.


Ronald Janssen

Привет Graeme_Grant thx за вашу реакцию. Будем его изучать.

Но почему вы говорите: "однако, похоже, что вы не хотите использовать шаблон MVVM, но хотите использовать систему привязки данных"?

У меня сложилось впечатление, что я использую шаблон MVVM с привязкой данных. (Может быть, не самый пуристский подход). У меня есть datacontext пользовательских элементов управления, настроенных на соответствующий ViewModel, а не на класс Model.

Я что-то упустил? ;-)

Graeme_Grant

Шаблон MVVM-это разделение представления и данных. Он позволяет тестировать без представления, переключать представления без изменения модели виртуальной машины и многое другое.

Привязка данных двусторонняя система уведомления об изменении данных. Вы можете использовать привязку данных, которая не соответствует шаблону MVVM. Привязка данных не требует представления/Xaml для работы.