Pull to refresh

Comments 14

Логика в формах. Я бы не учил такому джуниоров. MVVM в WPF — основа, которой надо учить сразу.
1. Соблюдайте общепринятый стиль кода;
2. Почитайте и изучите что такое MVC, MVP, MVVM;
3. 99% что с IoC те же проблемы у вас.

Вывод: Эта статья о том, как делать не надо.
UFO just landed and posted this here
В абстрактный метод передаются только два числовых параметра: выручка и затраты. Оба этих параметра рассчитываются в дочерней форме. Поэтому логику можно изменить для каждого конкретного случая.
Плохо. Если бы вы использовали data binding, то очень сильно удивились бы, сколько лишнего и кривого кода вы понаписали. Наверно, после таких вот архитектур и появляются статьи про то, что ООП уже не торт.
Согласен, Binding можно было бы использовать для того, чтобы поставить элементам формы в соответствие необходимые параметры. Но может ли байндинг решить главную проблему, затронутую в статье — абстрагирование общей логики?
Честное слово, вы сами себе придумали «главную проблему» и попытались её героически решить. Но тут нет никаких проблем, все решается стандартно. То, что вы вынесли в базовый класс, можно было бы сделать по-другому. Так то, что вы назвали «сохранением», решается стандартно из коробки через биндинги. Для расчета достаточно было добавить ещё одно св-во класса, которое бы и производило этот расчет, вывести это поле сразу на форму, а не заставлять бедного пользователя нажимать кнопки и закрывать после этого модальные окна. Могу посоветовать вам почитать про концепцию бизнес-объекта в книге Р. Лотка «c# и CSLA.Net»
Обозначения параметров:

Name — название картины
Type — тип, 0 — фильм, 1 — сериал
Cost — суммарный бюджет
Dues — прибыль с кинопроката
DuesTV — прибыль с телевидения
DuesExtra — доп. прибыль (DVD, прокаты)
CinemaPart — доля кинотеатров от прибыли
DistrPart — доля дистрибьюторов

ООП? Нет, не слышал… Интересно, вы правда не понимаете, что это плохая модель предметной области?


А в остальном — как вам уже неоднократно сказали, для подобных задач используется группа шаблонов Separated Presentation.

С таким же успехом можно был использовать WinForms, зачем WPF без биндингов? И разметка тяжело читается, т.к. лапша.

1)
Type — тип, 0 — фильм, 1 — сериал

private void movieList_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
if (((Movie)movieList.SelectedItem).Type == 0)
Type.Content = «Фильм»;
else
Type.Content = «Сериал»;
}

Тут очень не хватает enum для типа, converter вместо обработчика и switch с исключением по умолчанию, а то добавится еще «Мультфильм» c Type==2, а пользователь всё равно будет видеть «Сериал».

2)
На вкус и цвет именование у всех разное, но всё же
void calculate(… )
и
void _save_Click(… )
Смотрится несколько странно. Особенно вкупе с классами из самого .net. Вот тут «бинго» из трёх стилей на три строки кода:
    private void _save_Click(object sender, RoutedEventArgs e)
    {
        base.save(int.Parse(cost.Text), null, int.Parse(duesTV.Text),
            int.Parse(duesExtra.Text), null, null);
    }

3)
Собственно то, что уже писали, логику во View держать не надо. Там вообще ни одной строчки, относящейся к вычислениям, не должно быть.
И не надо будет заморачиваться с теми же конвертами string в int — wpf всё за вас сделает через биндинги.
Не используйте событие Click на кнопке, для этого есть команды. Они отлично сочетаются с паттерном MVVM и служат для разделения ответственности.
В правильно разработанном WPF приложении, .xaml.cs файлы, в большинстве случаев, содержат только код, сгенерированный студией, логика вынесена во ViewModel. И наследуются, соответственно ViewModel, а не вьюшки.
Постепенно начинаешь понимать, как грамотно разрабатывать проекты на WPF. Сейчас мне это как раз нужно. Если я в чём-то не прав, прошу поправить. Как я понял, у каждой формы должна быть своя ViewModel, которая, если нужно, наследуется от базовой, и Xaml-файл? Про MVVM я изучил кое-что. Суть его в том, что он изначально регистрирует нужные события во ViewModel, а обработчики с формы на эти события ссылаются. Вы говорите, что не следует использовать Click в разметке. Как предлагаете сделать это лучше? Единственный вариант, известный мне — подписка в коде:
button.Click += button_Click;
Грубо говоря, суть MVVM в том, что используете ViewModel в качестве связки между UI и доменной областью. Между UI и ViewModel организуется двухсторонний биндинг, который автоматически обновляет UI при изменении данных, а данные из UI через ViewModel идут обратно в доменную область. Валидация как правило тоже делается на уровне ViewModel.
При этом получается что у вас .xaml.cs практически пустой, все привязки задаются в xaml файле.
Click вообще не следует использовать, вместо этого есть команды. Есть стандартный паттерн RelayCommand (аналог DelegateCommand из майкрософтовского Prism):
RelayCommand
    public class RelayCommand : ICommand
    {
        #region Fields

        readonly Action<object> _execute;
        readonly Predicate<object> _canExecute;

        #endregion // Fields

        #region Constructors

        /// <summary>
        /// Creates a new command.
        /// </summary>
        /// <param name="execute">The execution logic.</param>
        /// <param name="canExecute">The execution status logic.</param>
        public RelayCommand(Action<object> execute, Predicate<object> canExecute = null)
        {
            if (execute == null)
                throw new ArgumentNullException("execute");

            _execute = execute;
            _canExecute = canExecute;
        }

        #endregion // Constructors

        #region ICommand Members

        [DebuggerStepThrough]
        public bool CanExecute(object parameter)
        {
            return _canExecute == null || _canExecute(parameter);
        }

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }

        public void Execute(object parameter)
        {
            _execute(parameter);
        }

        #endregion // ICommand Members
    }



Во ViewModel у вас есть
class ViewModel
{
    public ICommand DigitButtonCommand
    {
        get;
    }

    public ViewModel()
    {
        DigitButtonCommand = new RelayCommand((arg) => { });
    }             
}


Соответственно во вьюшке вы привязываете свойство DigitButtonCommand:
<Button Command="{Binding Path=DigitButtonCommand}" CommandParameter="7">7</Button>

CommandParameter придёт в качестве аргумента в обработчик (в данном случае 7).

Самое интересное во всём этом, что вы можете создавать дочерние вьюшки, используя ViewModel.
В родительскую вьюшку кладётся ContentControl:
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <ContentControl Grid.Column="0" Content="{Binding Path=Left}" />
    <ContentControl Grid.Column="1" Content="{Binding Path=Center}" />
    <ContentControl Grid.Column="2" Content="{Binding Path=Right}" />
</Grid>


В ресурсах задаётся шаблон:
<DataTemplate DataType="{x:Type vm:MainButtonsViewModel}">
    <vw:MainButtons/>
</DataTemplate>

, а в родительскую ViewModel добавляются свойства для биндинга ContentControl'ов:
/// <summary>
/// Get or set left panel.
/// </summary>
public object Left
{
    get
    {
        return _left;
    }
    set
    {
        _left = value;
        OnPropertyChanged();
    }
}

/// <summary>
/// Get or set center panel.
/// </summary>
public object Center
{
    get
    {
        return _center;
    }
    set
    {
        _center = value;
        OnPropertyChanged();
    }
}

/// <summary>
/// Get or set right panel.
/// </summary>
public object Right
{
    get
    {
        return _right;
    }
    set
    {
        _right = value;
        OnPropertyChanged();
    }
}


Магия начинается в тот момент, когда вы присваиваете, например свойству Left, дочернюю ViewModel типа MainButtonsViewModel. В этот момент WPF найдёт вьюшку в словаре (словарь должен быть подключен к ресурсам родительской вьюшки), которая соответствует MainButtonsViewModel (в данном случае MainButtons.xaml) и автоматически отобразит её в соответствующем ContentControl.
При этом вы работаете только с ViewModel, вам не надо заботиться об отображениях текста, о сокрытии контролов в рамках UI и т.п. Всё ваше приложение разделено на атомарные компоненты, каждый из которых имеет свою зону ответственности.
Спасибо за развёрнутый ответ, целая лекция по основам проектирования в трёх коротких абзацах!
Sign up to leave a comment.

Articles