MVVM WPF: жесткий код или абстрактные представления? - PullRequest
0 голосов
/ 20 апреля 2020

Я разрабатываю приложение WPF с использованием MVVM, где я показываю сообщения об ошибках / специальные диалоги через всплывающее окно в стиле лайтбокса. Эти подвиды являются пользовательскими элементами управления, отображаемыми ContentControl в главном представлении.

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

  • Изображение значка в левом верхнем углу
  • Текст заголовка рядом со значком
  • Текст сообщения в середине
  • 2 кнопки в правом нижнем углу

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

Но должен ли я? Есть ли выигрыш в производительности от этого? Похоже, что это подпадает под DRY, когда есть 8 подвидов с одинаковым рисунком сетки.

1 Ответ

1 голос
/ 20 апреля 2020

Dry не о производительности.

Речь идет об экономии времени на написании кода и на этапе обслуживания.

Хотя было бы более элегантно сделать один универсальный c re -используемое окно, вероятно, имеет определенную стоимость.

Стоит ли вам работа дороже, чем вы получаете? Решение о том, следует ли рационализировать в одно, возможно, более сложное представление или нет, должно основываться на своего рода анализе затрат и выгод.

Факторы, которые вы должны учитывать:

Сколько времени потребуется, чтобы сделать каждый вид?

Насколько сложна функциональность в каждом?

Сколько нужно усилий, чтобы сделать обобщенный c?

Сколько существует исключительных случаев и как сильно бы они усложнили создание этого дженерика c?

Сделало бы этот дженерик c неясной функциональностью и в какой степени это сделает обслуживание более дорогим?

Насколько вероятно, что вы Вам придется изменить внешний вид этих вещей?

Если вы вряд ли измените внешний вид, есть несколько крайних случаев, которые усложняют общий вид c, и внедрение вашей функциональности имеет сложности, тогда просто копирование и вставка разметки в каждое представление имеет некоторый смысл.

Редактировать:

Помните, что стиль можно использовать повторно.

Вот конкретный бит разметки для рассмотрения.

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="30"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="40"/>
    </Grid.RowDefinitions>
    <StackPanel Orientation="Horizontal">
        <Path Data="{Binding IconGeometry}"
              Stretch="Fill"
              Fill="Black"
              Height="28"
              Width="28"/>
        <TextBlock Text="{Binding Heading}"/>
    </StackPanel>
    <TextBlock Grid.Row="1"
                   Text="{Binding Message}"/>
        <ItemsControl 
            Grid.Row="2"
            ItemsSource="{Binding NamedCommandCollection}"
            HorizontalAlignment="Right">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                   <Button Content="{Binding ButtonText}" Command="{Binding ButtonCommand}"/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
      </ItemsControl>
</Grid>

Вы представляете для этого модель представления.

Эта модель представления реализует inotifypropertychanged и предоставляет строковое свойство для заголовка message et c.

Менее очевидные вещи здесь - это путь с геометрией, а не изображение. Это зависит от того, как ваша иконография будет выглядеть точно, но простая однотонная форма сейчас очень распространена.

Вы можете определить геометрию в словаре ресурсов, выбрать подходящую и выделить ее как свойство. Словари объединенных ресурсов go в application.current.resources, который в значительной степени является словарём в памяти объектов, на которые указывает строка вашего x: key.

Кнопки создаются с помощью элемента управления, который формирует шаблоны своих элементов. в горизонтальную линию кнопок. Создайте модель представления, представляющую кнопку.

строковое свойство для имени и команду relay или делегата для ButtonCommand.

Давайте назовем это ButtonVM.

Добавьте ButtonVM в наблюдаемую коллекцию Появится свойство NamedCommandCollection и вы получите кнопку. Добавьте один, два, три. Сколько бы ты ни любил. Вы можете заставить ButtonVM просто принять команду реле, которую вы создаете и поставляете, или иметь ее самостоятельно, и вы вводите действие. Вы можете захватывать переменные при динамическом построении действия.

Команда также может выполнять. Вы можете использовать это, чтобы уточнить, когда кнопка может быть нажата или нет. Например, у меня есть свойство IsBusy в базовой модели представления, которое я использую, чтобы указать, «запущена» ли какая-либо команда, чтобы избежать этого очень быстрого двойного щелчка, ломающего все.

Вот оно:

public class BaseViewModel : INotifyPropertyChanged
{
    private bool isBusy;
    [IgnoreDataMember]
    public bool IsBusy
    {
        get => isBusy;
        set => ToVal(ref isBusy, value, nameof(IsBusy));
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public void RaisePropertyChanged([CallerMemberName] String propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    public void ToObj<T>(ref T backer, T value, [CallerMemberName] string propertyName = null)
    {
        backer = value;
        this.RaisePropertyChanged(propertyName);
    }
    public void ToVal<T>(ref T backer, T value, [CallerMemberName] string propertyName = null)
    {
        if (Equals(backer, value))
        {
            return;
        }
        backer = value;
        this.RaisePropertyChanged(propertyName);
        return;
    }
}

Icommand имеет canexecute bool и отключит элемент управления, к которому привязана команда, если она ложна. Тем не менее, это зависит от командного менеджера, решившего выполнить запрос и может отключить этот элемент управления. Есть обстоятельства, когда этого не произойдет достаточно быстро. Следовательно, лучше использовать bool для защиты кода в команде.

Довольно случайный пример реального кода:

    private RelayCommand newMapCommand;

    public RelayCommand NewMapCommand
    {
        get
        {
            return newMapCommand
            ?? (newMapCommand = new RelayCommand(
              () =>
             {
                 if (IsBusy)
                 {
                     return;
                 }
                 ResetMap();
                 IsBusy = false;
             },
             ( ) => !IsBusy
             ));

        }
    }

Команда ретрансляции находится в mvvmlight. Поскольку в настоящее время я работаю в ядре net и в commandwpf есть зависимость от net old, я нашел источник нужных мне битов mvvmlight. Я сохраняю пространства имен, поскольку Лоран, вероятно, в конечном итоге решит эту проблему, или net 5 может устранить проблему.

Пользовательский контроль может сам содержать пользовательский контроль. Если вам нужна гибкость, тогда он может иметь контент-контроль и шаблон для того, что связано с его контентом.

Сначала он используется для viewmodel, распространенного способа переключения контента для навигации и т. Д. c. Я написал пример, чтобы объяснить зло страниц: ^) https://social.technet.microsoft.com/wiki/contents/articles/52485.wpf-tips-and-tricks-using-contentcontrol-instead-of-frame-and-page-for-navigation.aspx

...