Будет ли шаблон MVVM соответствовать требованиям этого приложения?

1

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

Это в конечном итоге будет довольно большим приложением, поэтому я хочу быть уверенным, что дизайн, который у меня есть, хорош с самого начала. Я рассмотрел шаблон модели Model-View-View Model, так как не будет данных, передаваемых обратно в представление, я не думаю, что это лучший шаблон для использования.

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

Является ли MVC более подходящей моделью здесь? Я знаю, что это довольно редко, и MVVM, по-видимому, является образцом выбора, но, опять же, я чувствую, что, поскольку данные не передаются обратно в представление о том, что MVVM не подходит.

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

  • 0
    Вы можете просто сделать это с прямым WPF или даже консольным приложением.
  • 0
    Отредактировал вопрос, может быть, вы можете переместить его в более подходящее место, например programmers.stackexchange.com ?
Теги:
model-view-controller
wpf
mvvm
design

1 ответ

4
Лучший ответ

Добро пожаловать в StackOverflow! Я постараюсь ответить на ваш первый вопрос как можно лучше: D

Из того, что я прочитал, я собирался броситься на клавиатуру и просто сказать вам: "Да, пойдите, чтобы помахать", но вместо этого я решил создать вам действительно маленький пример того, что может принести MVVM-шаблон вы.

Лично я был немного похож на вас, скептически относился к преимуществам и дополнительной работе, которые он мог понести; но позвольте мне сказать вам, что это действительно того стоит. Только недавно я принял образец, и я не могу перестать думать, почему я этого не сделал раньше? Это такая экономия времени, сохраняет озабоченности разделенными и действительно простыми.

Так вот пример!

Изображение 174551

Теперь шаблон MVVM

Здесь схема взаимодействия компонентов, обратите внимание, что это цепочка:

Просмотреть <-> ViewModel <-> Модель

(вы скоро получите преимущества от этого)

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

public class EncryptorModel
{
    public string Cipher(string text)
    {
        char[] enumerable = text.Select(s => ++s).ToArray();
        var cipher = new string(enumerable);
        return cipher;
    }
}

ViewModel (вид вашей модели): теперь это становится интересным, в то время как преимущества этого компонента на первый взгляд очевидны, они действительно присутствуют, и я попытаюсь продать их вам: D

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

Как вы можете видеть ниже: он содержит свойства для этого примера шифрования; передает данные из представления в/из модели (автоматически благодаря привязке данных WPF). Наконец, в нем содержатся команды, которые триггеры View.

public class EncryptorViewModel : ViewModelBase
{
    private RelayCommand _cipher;
    private string _inputText;
    private string _outputText;

    public EncryptorViewModel()
    {
        Model = new EncryptorModel();
    }

    private EncryptorModel Model { get; set; }

    #region Public properties

    public string InputText
    {
        get { return _inputText; }
        set
        {
            _inputText = value;
            RaisePropertyChanged();
            Cipher.RaiseCanExecuteChanged();
        }
    }

    public string OutputText
    {
        get { return _outputText; }
        set
        {
            _outputText = value;
            RaisePropertyChanged();
        }
    }

    #endregion

    #region Commands

    public RelayCommand Cipher
    {
        get { return _cipher ?? (_cipher = new RelayCommand(CipherExecute, CipherCanExecute)); }
    }

    private void CipherExecute()
    {
        OutputText = Model.Cipher(InputText);
    }

    private bool CipherCanExecute()
    {
        return !string.IsNullOrWhiteSpace(InputText);
    }

    #endregion
}

Просмотр: нечего сказать, кроме того, что он представляет ваши приложения и вызывает команды в ViewModel.

<Window x:Class="WpfApplication1.EncryptorView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:wpfApplication1="clr-namespace:WpfApplication1"
        Title="EncryptorView"
        Width="165"
        Height="188">
    <Window.Resources>
        <wpfApplication1:EncryptorViewModel x:Key="ViewModel" />
    </Window.Resources>
    <Grid DataContext="{Binding Source={StaticResource ViewModel}}">
        <StackPanel>
            <TextBlock Text="Input text" />
            <TextBox Text="{Binding InputText, UpdateSourceTrigger=PropertyChanged}" />
            <TextBlock Text="Output text" />
            <TextBox Text="{Binding OutputText}" />
            <Button Command="{Binding Cipher}" Content="Cipher" />
        </StackPanel>
    </Grid>
</Window>

Вывод

Я мог и продолжил более длинный ответ, но отменил в пользу того, чтобы оставаться простым, что вы должны сохранить на данный момент:

  • View просто привязывается к свойствам, которые пользователь должен видеть/манипулировать и связывать с командами, которые пользователь должен выполнять на модели

  • ViewModel представляет упрощенное представление Модели, оно показывает только то, что требуется View и выполняет команды на модели

  • Модель - это строго ваше профессиональное поле, задача заключается в шифровании/расшифровке, ничего больше!

Окончательный вывод: проблемы остаются разделенными с использованием MVVM, приложения, использующие этот шаблон, просты в обслуживании. Для меня это не было очевидно, если я не провел 3 дня с MVVM, поэтому я могу только поощрять вас сделать это, ваши проекты программирования явно выиграют от этого.

Используемая среда:

Я использовал Galasoft MVVM Light: http://www.mvvmlight.net/installing/nuget/

(только библиотеки библиотеки MVVM Light)

Я добровольно пропустил часть локатора службы, вы найдете ее в шаблонах проекта Visual Studio здесь: http://www.mvvmlight.net/installing

РЕДАКТИРОВАТЬ

Вот несколько сценариев, которые обновляют "исходный" сценарий.

Несколько ViewModels:

Правило должно иметь один ViewModel для каждого представления (или пользовательский интерфейс), поэтому, если ваше приложение. имеет 2 окна, тогда у вас будет 2 ViewModel.

Разделите модель между двумя или более ViewModels:

Если, например, вы можете подтвердить, что оба окна могут работать на одной и той же модели, тогда вы можете иметь только 1 модель, и вместо этого вы App.xaml ее в App.xaml:

App.xaml:

<Application x:Class="WpfApplication1.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:wpfApplication1="clr-namespace:WpfApplication1"
             StartupUri="EncryptorView.xaml">
    <Application.Resources>
        <wpfApplication1:EncryptorModel x:Key="Model1"/>
    </Application.Resources>
</Application>

EncryptorViewModel1:

public class EncryptorViewModel1 : ViewModelBase
{
    //private EncryptorModel Model { get; set; }

    public EncryptorViewMode1l()
    {
        // Model = new EncryptorModel();

        // Now you retrieve the model in App.xaml instead of declaring a private one above
        var model =(EncryptorModel) Application.Current.FindResource("Model1");
    }
}

Сценарий: использование нескольких шифров в одном представлении

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

Изображение 174551Изображение 174551

Мы используем ту же ViewModel,

  • мы добавляем свойства AvailableEncryptors и CurrentEncryptor
  • мы модифицируем CipherCanExecute так, чтобы он учитывал CurrentEncryptor, пользователь сможет шифровать только тогда, когда установлен InputText и выбран InputText
  • Также CipherExecute изменяется немного, то EncryptorModel шифры в соответствии указанной строкой и шифратор

Обновлен ViewModel:

public class EncryptorViewModel : ViewModelBase
{
    private RelayCommand _cipher;
    private IEncryptor _currentEncryptor;
    private string _inputText;
    private string _outputText;

    public EncryptorViewModel()
    {
        Model = new EncryptorModel();
    }

    private EncryptorModel Model { get; set; }

    public IEnumerable<IEncryptor> AvailableEncryptors
    {
        get
        {
            Type type = typeof (IEncryptor);
            IEnumerable<IEncryptor> encryptors =
                Assembly
                    .GetExecutingAssembly()
                    .GetTypes()
                    .Where(p => type.IsAssignableFrom(p) && !p.IsInterface && !p.IsAbstract)
                    .Select(s => (IEncryptor) Activator.CreateInstance(s));
            return encryptors;
        }
    }

    public IEncryptor CurrentEncryptor
    {
        get { return _currentEncryptor; }
        set
        {
            _currentEncryptor = value;
            RaisePropertyChanged();
            Cipher.RaiseCanExecuteChanged();
        }
    }

    #region Public properties

    public string InputText
    {
        get { return _inputText; }
        set
        {
            _inputText = value;
            RaisePropertyChanged();
            Cipher.RaiseCanExecuteChanged();
        }
    }

    public string OutputText
    {
        get { return _outputText; }
        set
        {
            _outputText = value;
            RaisePropertyChanged();
        }
    }

    #endregion

    #region Commands

    public RelayCommand Cipher
    {
        get { return _cipher ?? (_cipher = new RelayCommand(CipherExecute, CipherCanExecute)); }
    }

    private void CipherExecute()
    {
        OutputText = Model.Cipher(CurrentEncryptor, InputText);
    }

    private bool CipherCanExecute()
    {
        return CurrentEncryptor != null && !string.IsNullOrWhiteSpace(InputText);
    }

    #endregion
}

Примечание. Возможно, у вас может возникнуть соблазн полностью удалить модель и сделать все внутри ViewModel, но не делать этого, даже если ViewModel просто выступает в качестве шлюза, и вы больше не должны использовать возможность реализации связанной с шифрованием логики в модели, а не ViewModel.

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

Затем я обновил модель для вызова шифрования всякий раз, когда мы хотим, чтобы он зашифровал что-то:

public class EncryptorModel
{
    public string Cipher(IEncryptor encryptor, string text)
    {
        return encryptor.Cipher(text);
    }
}

Наконец, я реализовал шифры:

public interface IEncryptor
{
    string Description { get; }
    string Cipher(string text);
}

public class Encryptor1 : IEncryptor
{
    #region IEncryptor Members

    public string Description
    {
        get { return "Encryptor 1"; }
    }

    public string Cipher(string text)
    {
        char[] enumerable = text.Select(s => ++s).ToArray();
        var cipher = new string(enumerable);
        return cipher;
    }

    #endregion
}

public class Encryptor2 : IEncryptor
{
    #region IEncryptor Members

    public string Description
    {
        get { return "Encryptor 2"; }
    }

    public string Cipher(string text)
    {
        char[] enumerable = text.Select(s => --s).ToArray();
        var cipher = new string(enumerable);
        return cipher;
    }

    #endregion
}

И обновленное представление:

<Window x:Class="WpfApplication1.EncryptorView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:wpfApplication1="clr-namespace:WpfApplication1"
        Title="EncryptorView"
        Width="165"
        Height="188">
    <Window.Resources>
        <wpfApplication1:EncryptorViewModel x:Key="ModelView" />
    </Window.Resources>
    <Grid DataContext="{Binding Source={StaticResource ModelView}}">
        <StackPanel>
            <TextBlock Text="Select an encryptor" />
            <ComboBox ItemsSource="{Binding AvailableEncryptors}" SelectedItem="{Binding CurrentEncryptor}">
                <ComboBox.ItemTemplate>
                    <DataTemplate DataType="wpfApplication1:IEncryptor">
                        <TextBlock Text="{Binding Description}" />
                    </DataTemplate>
                </ComboBox.ItemTemplate>
            </ComboBox>
            <TextBlock Text="Input text" />
            <TextBox Text="{Binding InputText, UpdateSourceTrigger=PropertyChanged}" />
            <TextBlock Text="Output text" />
            <TextBox Text="{Binding OutputText}" />
            <Button Command="{Binding Cipher}" Content="Cipher" />
        </StackPanel>
    </Grid>
</Window>

Вывод

Итак, как вы можете видеть, я немного пытался реализовать новые типы, но это окупается, каждый метод шифрования является независимым, а также шифр, который хорош. В конце концов, шифр не является методом шифрования, поэтому они лучше разделены.

  • 1
    +1. +10, если б я мог за отличный, подробный, исчерпывающий ответ, что тоже правильно . Отсутствие MVVM означает определенно больше усилий в WPF независимо от типа проекта, о котором вы говорите.
  • 0
    Спасибо друг ! : D
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню