Comments 14
Логика в формах. Я бы не учил такому джуниоров. MVVM в WPF — основа, которой надо учить сразу.
+7
1. Соблюдайте общепринятый стиль кода;
2. Почитайте и изучите что такое MVC, MVP, MVVM;
3. 99% что с IoC те же проблемы у вас.
Вывод: Эта статья о том, как делать не надо.
2. Почитайте и изучите что такое MVC, MVP, MVVM;
3. 99% что с IoC те же проблемы у вас.
Вывод: Эта статья о том, как делать не надо.
+6
UFO just landed and posted this here
Плохо. Если бы вы использовали data binding, то очень сильно удивились бы, сколько лишнего и кривого кода вы понаписали. Наверно, после таких вот архитектур и появляются статьи про то, что ООП уже не торт.
+2
Согласен, Binding можно было бы использовать для того, чтобы поставить элементам формы в соответствие необходимые параметры. Но может ли байндинг решить главную проблему, затронутую в статье — абстрагирование общей логики?
-1
Честное слово, вы сами себе придумали «главную проблему» и попытались её героически решить. Но тут нет никаких проблем, все решается стандартно. То, что вы вынесли в базовый класс, можно было бы сделать по-другому. Так то, что вы назвали «сохранением», решается стандартно из коробки через биндинги. Для расчета достаточно было добавить ещё одно св-во класса, которое бы и производило этот расчет, вывести это поле сразу на форму, а не заставлять бедного пользователя нажимать кнопки и закрывать после этого модальные окна. Могу посоветовать вам почитать про концепцию бизнес-объекта в книге Р. Лотка «c# и CSLA.Net»
0
Обозначения параметров:
Name — название картины
Type — тип, 0 — фильм, 1 — сериал
Cost — суммарный бюджет
Dues — прибыль с кинопроката
DuesTV — прибыль с телевидения
DuesExtra — доп. прибыль (DVD, прокаты)
CinemaPart — доля кинотеатров от прибыли
DistrPart — доля дистрибьюторов
ООП? Нет, не слышал… Интересно, вы правда не понимаете, что это плохая модель предметной области?
А в остальном — как вам уже неоднократно сказали, для подобных задач используется группа шаблонов Separated Presentation.
+3
С таким же успехом можно был использовать WinForms, зачем WPF без биндингов? И разметка тяжело читается, т.к. лапша.
0
1)
Тут очень не хватает enum для типа, converter вместо обработчика и switch с исключением по умолчанию, а то добавится еще «Мультфильм» c Type==2, а пользователь всё равно будет видеть «Сериал».
2)
На вкус и цвет именование у всех разное, но всё же
void calculate(… )
и
void _save_Click(… )
Смотрится несколько странно. Особенно вкупе с классами из самого .net. Вот тут «бинго» из трёх стилей на три строки кода:
3)
Собственно то, что уже писали, логику во View держать не надо. Там вообще ни одной строчки, относящейся к вычислениям, не должно быть.
И не надо будет заморачиваться с теми же конвертами string в int — wpf всё за вас сделает через биндинги.
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 всё за вас сделает через биндинги.
+1
Не используйте событие Click на кнопке, для этого есть команды. Они отлично сочетаются с паттерном MVVM и служат для разделения ответственности.
В правильно разработанном WPF приложении, .xaml.cs файлы, в большинстве случаев, содержат только код, сгенерированный студией, логика вынесена во ViewModel. И наследуются, соответственно ViewModel, а не вьюшки.
В правильно разработанном WPF приложении, .xaml.cs файлы, в большинстве случаев, содержат только код, сгенерированный студией, логика вынесена во ViewModel. И наследуются, соответственно ViewModel, а не вьюшки.
0
Постепенно начинаешь понимать, как грамотно разрабатывать проекты на WPF. Сейчас мне это как раз нужно. Если я в чём-то не прав, прошу поправить. Как я понял, у каждой формы должна быть своя ViewModel, которая, если нужно, наследуется от базовой, и Xaml-файл? Про MVVM я изучил кое-что. Суть его в том, что он изначально регистрирует нужные события во ViewModel, а обработчики с формы на эти события ссылаются. Вы говорите, что не следует использовать Click в разметке. Как предлагаете сделать это лучше? Единственный вариант, известный мне — подписка в коде:
button.Click += button_Click;
button.Click += button_Click;
0
Грубо говоря, суть MVVM в том, что используете ViewModel в качестве связки между UI и доменной областью. Между UI и ViewModel организуется двухсторонний биндинг, который автоматически обновляет UI при изменении данных, а данные из UI через ViewModel идут обратно в доменную область. Валидация как правило тоже делается на уровне ViewModel.
При этом получается что у вас .xaml.cs практически пустой, все привязки задаются в xaml файле.
Click вообще не следует использовать, вместо этого есть команды. Есть стандартный паттерн RelayCommand (аналог DelegateCommand из майкрософтовского Prism):
Во ViewModel у вас есть
Соответственно во вьюшке вы привязываете свойство DigitButtonCommand:
CommandParameter придёт в качестве аргумента в обработчик (в данном случае 7).
Самое интересное во всём этом, что вы можете создавать дочерние вьюшки, используя ViewModel.
В родительскую вьюшку кладётся ContentControl:
В ресурсах задаётся шаблон:
, а в родительскую ViewModel добавляются свойства для биндинга ContentControl'ов:
Магия начинается в тот момент, когда вы присваиваете, например свойству Left, дочернюю ViewModel типа MainButtonsViewModel. В этот момент WPF найдёт вьюшку в словаре (словарь должен быть подключен к ресурсам родительской вьюшки), которая соответствует MainButtonsViewModel (в данном случае MainButtons.xaml) и автоматически отобразит её в соответствующем ContentControl.
При этом вы работаете только с ViewModel, вам не надо заботиться об отображениях текста, о сокрытии контролов в рамках UI и т.п. Всё ваше приложение разделено на атомарные компоненты, каждый из которых имеет свою зону ответственности.
При этом получается что у вас .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 и т.п. Всё ваше приложение разделено на атомарные компоненты, каждый из которых имеет свою зону ответственности.
0
Sign up to leave a comment.
Проектирование идентичных форм в WPF с применением абстрактных классов