Форум программистов, компьютерный форум, киберфорум
C#: WPF, UWP и Silverlight
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.59/34: Рейтинг темы: голосов - 34, средняя оценка - 4.59
1 / 1 / 1
Регистрация: 30.01.2013
Сообщений: 74
1

Где располагать логику приложения, когда используем паттерн mvvm?

28.03.2017, 19:20. Показов 7055. Ответов 34
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Изучаю wpf и паттерн mvvm.
Никогда не задумывался, где что располагать, я считал (считаю пока), что представление - это пользовательский интерфейс; модель - это данные, управление этих данных, логика обработки их, да вся логика; представление-модель - это просто то место, где идет соединение модели и представления.
Но прав ли я ? Везде пишут, что во view-model размещается вся логика нашего приложения. А какой смысл несут данные слова? Ведь я же не буду все размещать в классе ViewModel?
к примеру, я делаю так: создаю папки model, view, viewmodel.
Во view созданию какое-нибудь окно. В модели создаю класс FileModel, но и при этом, к примеру, я создаю в модели также работу с этими данными: класс FileManipulation, который содержит какую-нибудь логику обработки данных. И вью-модел у меня является тем мостом, между моделью и вью. В этом вью-модель я обращаюсь к классу FileManipulation, беру данные оттуда и вывожу их.
По сути, это все формальность же, в какой папке (model или viewmodel) я размещу свой класс FileManipulation, но загрузился, а как будет все-таки корректнее, где должны быть такие классы? Ведь при реализации чего-то, таких классов FileManipulation может быть 20 штук?
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
28.03.2017, 19:20
Ответы с готовыми решениями:

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

Паттерн MVVM
Подскажите пожалуйста какой-нибудь хороший туториал по MVVM (WPF)

Mvvm паттерн
Форумчане , накидал не большое приложение (кошелек) в универе задавали. Изучаю wpf и mvvm не так...

Паттерн MVVM
Учитывая мои предыдущие вопросы по теме...

34
294 / 234 / 58
Регистрация: 03.02.2011
Сообщений: 1,993
Записей в блоге: 1
22.04.2017, 21:49 21
Author24 — интернет-сервис помощи студентам
Цитата Сообщение от HF Посмотреть сообщение
но не смог к нему подбиндится и вообще сделать чтобы оно с нужными данными работало
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class SchcolarViewModel : INotifyPropertyChanged
{
   public Schcolar Scholar {get;set;}
   public string FIO => Scholar.Name + Scholar.Surname + Scholar.SecondName;
 
   public SchcolarViewModel (Scholar _sch)
   {
      //не забыть проверку на null
      Scholar = _sch;
      Scholar.ItemPropertyChanged += ScholarOnItemPropertyChanged;
   }
 
   private void ScholarOnItemPropertyChanged(object sender, ItemPropertyChangedEventArgs itemPropertyChangedEventArgs)
   {
      if (itemPropertyChangedEventArgs.PropertyName == (nameof(Scholar.Name) ||
          itemPropertyChangedEventArgs.PropertyName == (nameof(Scholar.Surname) ||
          itemPropertyChangedEventArgs.PropertyName == (nameof(Scholar.SecondName)
            {
                OnPropertyChanged(nameof(FIO));
            }
   }
//Реализовать интерфейс
}
XML
1
2
3
4
<DataGridTextColumn x:Name="ФИО"
                                    Width="25"
                                    Binding="{Binding Path=FIO, , UpdateSourceTrigger=PropertyChanged}"
                                    Header="ФИО"/>
Добавлено через 2 минуты
Schcolar - тоже должен реализовывать (или как там говорят...имплементировать ) INotifyPropertyChanged
1
Жуткая тВарЬ
393 / 328 / 135
Регистрация: 06.02.2015
Сообщений: 962
Записей в блоге: 1
22.04.2017, 22:07 22
skilllab, Какой то бездарный пример, лучше сделать так:
XML
1
2
3
4
5
6
7
8
9
10
11
 <DataGridTextColumn x:Name="ФИО"
                                    Width="25"
                                    Header="ФИО">
                    <DataGridTextColumn.Binding>
                        <MultiBinding StringFormat="{}{0} {1} {2}">
                            <Binding Path="Name" />
                            <Binding Path="Surname" />
                            <Binding Path="SecondName" />
                        </MultiBinding>
                    </DataGridTextColumn.Binding>
                </DataGridTextColumn>
Во вторых что Вы там обновлять собрались (UpdateSourceTrigger=PropertyChanged) если свойство Fio READONLY
2
294 / 234 / 58
Регистрация: 03.02.2011
Сообщений: 1,993
Записей в блоге: 1
22.04.2017, 22:27 23
Цитата Сообщение от amarf Посмотреть сообщение
Какой то бездарный пример

Какой есть.
Цитата Сообщение от amarf Посмотреть сообщение
лучше сделать так
Кому лучше? ViewModel-и или типа чтоб попроще было?
Может тогда вообще забить на эту VM? Чо там... пару свойств текстовых

Добавлено через 1 минуту
Цитата Сообщение от amarf Посмотреть сообщение
если свойство Fio READONLY
Не скажу всё есть в посте.
0
Жуткая тВарЬ
393 / 328 / 135
Регистрация: 06.02.2015
Сообщений: 962
Записей в блоге: 1
22.04.2017, 22:36 24
Цитата Сообщение от skilllab Посмотреть сообщение
Не скажу всё есть в посте.
Цитата Сообщение от skilllab Посмотреть сообщение
public string FIO => Scholar.Name + Scholar.Surname + Scholar.SecondName;
Эли это не ReadOnly (не имеющий метода сет) то я "испанский летчик"...

Цитата Сообщение от skilllab Посмотреть сообщение
Кому лучше? ViewModel-и или типа чтоб попроще было?
Может тогда вообще забить на эту VM? Чо там... пару свойств текстовых
Да! именно так в данном случае вьюмодель вообще не нужна - если каждый "чих" оборачивать во вьюмодель, то вы скоро утонете в собственном коде. ВьюМодели создаются под конкретные ситуации и если надо только отображать данные школьников (и менять их), то создается одна вьюмодель которая оперирует всеми школьниками, а не по одной вьюмодели на каждого школьника

Добавлено через 2 минуты
И вот мне интересно, почему все на форуме используют явную имплементацию INotifyPropertyChanged - это же прошлый век ???
0
294 / 234 / 58
Регистрация: 03.02.2011
Сообщений: 1,993
Записей в блоге: 1
22.04.2017, 22:44 25
Цитата Сообщение от amarf Посмотреть сообщение
Эли это не ReadOnly
Зачем ему SET? Это составное свойство. Вы ж его сами в XAML стрингформатом запихнули.
Цитата Сообщение от amarf Посмотреть сообщение
если каждый "чих" оборачивать во вьюмодель, то вы скоро утонете в собственном коде
Вот я так послушал один раз...может и вас... и сидел потом перебивал биндинги в XAML простынке, ибо чуть усложнилась логика и всё. Ваш пример лишь "вариация на тему", не более.

Цитата Сообщение от amarf Посмотреть сообщение
то создается одна вьюмодель которая оперирует всеми школьниками
Ну, вам виднее что там у HF.

Цитата Сообщение от amarf Посмотреть сообщение
используют явную имплементацию INotifyPropertyChanged - это же прошлый век
Ага)))) И снова Fody какой нибудь с аспектами. А потом поиск в гугле, а как же в этом Fody подписываться то... А как же посмотреть кто уведомляет и кого в дебаге....
И снова, это лишь ваша "вариация на тему".
0
Жуткая тВарЬ
393 / 328 / 135
Регистрация: 06.02.2015
Сообщений: 962
Записей в блоге: 1
22.04.2017, 22:54 26
Цитата Сообщение от skilllab Посмотреть сообщение
Вот я так послушал один раз...может и вас... и сидел перебивал биндинги в XAML простынке, ибо чуть усложнилась логика и всё. Ваш пример лишь "вариация на тему", не более.
Значит у тебя была хреново составлена архитектура, ибо перебрать байдинги в случае изменения Модели на Вьюмодель 5 минутное дело - это я тебе говорю по опыту разработки проектов со сложным UI интерфесом - ибо такая ситуация достаточно частая, когда документация по разработки меняется уже после того как ты написал функционал...

Цитата Сообщение от skilllab Посмотреть сообщение
Ага)))) И снова Fody какой нибудь с аспектами. А потом поиск в гугле, а как же в этом Fody подписываться то... А как же посмотреть кто уведомляет и кого в дебаге....
И снова, это лишь ваша "вариация на тему".
Именно Fody, а если уж надо подписываться то либо по простому через
C#
1
(this as INotifyPropertyChanged).PropertyChanged += ....
Либо через сигнатуру методов типа OnPropertyNameChanged()

Не знание - это не невежество, я честно говоря не помню что бы когда то у меня возникали проблемы с дебагом при использовании Fody, потому что их по определению не должно быть...
0
294 / 234 / 58
Регистрация: 03.02.2011
Сообщений: 1,993
Записей в блоге: 1
22.04.2017, 23:28 27
Цитата Сообщение от amarf Посмотреть сообщение
была хреново
Именно, перебил с прямой привязки к модели - и стала нормальной. В этом и суть.
Цитата Сообщение от amarf Посмотреть сообщение
ибо перебрать байдинги в случае изменения Модели на Вьюмодель 5 минутное дело
Ну и? И зачем сразу делать так, как ты посоветовал и назвал "правильным"? Ещё раз повторю - это лишь твои убеждения что у тебя правильный код в сообщении 22. Я же не утверждал что мой пример единственно верен В отличие от тебя.
Цитата Сообщение от amarf Посмотреть сообщение
(this as INotifyPropertyChanged).PropertyChanged += ....
Жуть. as Где тут у тебя в коде показано что не вернёт null или Exception? Да и вообще что this имплементирует INotify...?
Если уж делать, то в классе модели (или где ты там подписываешься) просто добавить строчку
C#
1
public event PropertyChangedEventHandler PropertyChanged;
И повторюсь - эта инфа ИЗ ГУГЛА. Что означает что чтобы вообще дошло как надо сделать - надо сидеть и рыскать по стаковерфлоу как там сделали.
-------------------------
Так что там с SET?
Цитата Сообщение от amarf Посмотреть сообщение
<DataGridTextColumn x:Name="ФИО"
* * * * * * * * * * * * * * * * * *Width="25"
* * * * * * * * * * * * * * * * * *Header="ФИО">
* * * * * * * * * * <DataGridTextColumn.Binding>
* * * * * * * * * * * * <MultiBinding StringFormat="{}{0} {1} {2}">
* * * * * * * * * * * * * * <Binding Path="Name" />
* * * * * * * * * * * * * * <Binding Path="Surname" />
* * * * * * * * * * * * * * <Binding Path="SecondName" />
* * * * * * * * * * * * </MultiBinding>
* * * * * * * * * * </DataGridTextColumn.Binding>
* * * * * * * * </DataGridTextColumn>
Где тут SET и как им воспользоваться? Или пагодь...изменяя какой нибудь Name изменится свойство? Ах дааа....
Цитата Сообщение от skilllab Посмотреть сообщение
public string FIO => Scholar.Name + Scholar.Surname + Scholar.SecondName;
Цитата Сообщение от skilllab Посмотреть сообщение
if (itemPropertyChangedEventArgs.PropertyName == (nameof(Scholar.Name) ||
* * * * * itemPropertyChangedEventArgs.PropertyName == (nameof(Scholar.Surname) ||
* * * * * itemPropertyChangedEventArgs.PropertyName == (nameof(Scholar.SecondName)
* * * * * * {
* * * * * * * * OnPropertyChanged(nameof(FIO));
* * * * * * }
Добавлено через 2 минуты
Цитата Сообщение от amarf Посмотреть сообщение
что бы когда то у меня возникали проблемы с дебагом при использовании Fody
У тебя нет, а у другой части пользователей Visual Studio окошечко "В данный момент исходный код не доступен для просмотра" при пошаговом - возникает. Госспади...всезнающий Ну серъёзно - лучше б просто в гугл отправил.
0
Жуткая тВарЬ
393 / 328 / 135
Регистрация: 06.02.2015
Сообщений: 962
Записей в блоге: 1
22.04.2017, 23:45 28
Блин! Это как с бараном пытаться разговаривать - ты ему о высоких материях, а у него в голове лишь ворота перед его глазами... на этом я думаю мы с тобой skilllab, закончим...
П.С.
Цитата Сообщение от skilllab Посмотреть сообщение
Так что там с SET?
- перечитай внимательно пост 22 может осмыслишь что имелось ввиду... По поводу изменения имен свойств, а так же null или Exception и остального аналогичного бормотанья, я могу сказать одно - это лечится, со временем, с опытом...
0
294 / 234 / 58
Регистрация: 03.02.2011
Сообщений: 1,993
Записей в блоге: 1
22.04.2017, 23:51 29
Цитата Сообщение от amarf Посмотреть сообщение
ты ему о высоких материях
И тебе удачи с твоими "воротами"
0
HF
1163 / 749 / 181
Регистрация: 09.09.2011
Сообщений: 2,314
Записей в блоге: 2
23.04.2017, 00:38 30
Приношу извинения за неточно сформулированную мысль. Сейчас подробнее распишу.

Проблема началась с того что я не могу получить данные из поля FIO, потому что всё это реализовано так:
C#
1
2
3
4
5
6
7
8
        <ListBox Grid.Column="0" ItemsSource="{Binding Schcolars}"
                 SelectedItem="{Binding SelectedSchcolar}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Margin="5">
                        <TextBlock Text="{Binding Path=SurName}" FontSize="18" />
...
                        <TextBlock Text="{Binding FIO}" />
Все текст блоки ищут привязку относительно указанного SelectedItem. А как явно указать что именно для этого текста нужен SchcolarViewModel.FIO я никак не могу понять. Получается только через relativesource и ancestor, это длинно и непонятно и не совсем верно работает. В итоге я уже делал как написал "amarf". Но как правильно сказал skilllab нет возможности сделать SET.
Поэтому-то я и решил перенести формирование ФИО в другие места - например в саму модель Schkolar. Но увидел эту тему и решил спросить - будет ли это уместно, реализовывать подобные методы прямо в модели. По идее как раз ViewModel и должен этим заниматься. Но... проблема.

Помогите подбиндится к FIO.
0
294 / 234 / 58
Регистрация: 03.02.2011
Сообщений: 1,993
Записей в блоге: 1
23.04.2017, 10:40 31
Цитата Сообщение от HF Посмотреть сообщение
Все текст блоки ищут привязку относительно указанного SelectedItem
Все текстблоки ищут путь в коллекции Schcolars, а не в SelectedItem.
Цитата Сообщение от HF Посмотреть сообщение
Но как правильно сказал skilllab нет возможности сделать SET.
Я там вообще о другом. Зачем вам SET на составном свойстве? Чтоб его потом парсить?

Вам предложили 2 разных подхода к вашей ситуации, а можете ещё и третий свой сделать
Цитата Сообщение от HF Посмотреть сообщение
формирование ФИО в другие места - например в саму модель Schkolar
Что не получилось то, применительно к вышеуказанным трём методам?
0
HF
1163 / 749 / 181
Регистрация: 09.09.2011
Сообщений: 2,314
Записей в блоге: 2
23.04.2017, 11:51 32
Цитата Сообщение от skilllab Посмотреть сообщение
Что не получилось то, применительно к вышеуказанным трём методам?
C#
1
public string FIO => Scholar.Name + Scholar.Surname + Scholar.SecondName;
Пусто вместо данных.
Цитата Сообщение от skilllab Посмотреть сообщение
Все текстблоки ищут путь в коллекции Schcolars.
А FIO находится в SchcolarViewModel. Как ему указать новый путь? или отменить начало поиска "в коллекции Schcolars"?
0
294 / 234 / 58
Регистрация: 03.02.2011
Сообщений: 1,993
Записей в блоге: 1
23.04.2017, 13:26 33
HF, уффф..
Цитата Сообщение от HF Посмотреть сообщение
В итоге я уже делал как написал "amarf".
на этом и остановитесь. А иначе проще будет взять ваш проект, да самому всё сделать.
0
Жуткая тВарЬ
393 / 328 / 135
Регистрация: 06.02.2015
Сообщений: 962
Записей в блоге: 1
23.04.2017, 14:22 34
Вариант 1:
MultiValueConverter

XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<Window x:Class="MS_TEXTBOX.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MS_TEXTBOX"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        Title="MainWindow"
        Width="525"
        Height="350">
    <Window.DataContext>
        <local:ViewModel />
    </Window.DataContext>
    <Grid>
        <ListBox Grid.Column="0"
                 ItemsSource="{Binding Schcolars}"
                 SelectedItem="{Binding SelectedSchcolar}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Margin="5">
                        <TextBox>
                            <TextBox.Resources>
                                <local:SchcolarFullNameConverter x:Key="SchcolarFullNameConverter" />
                            </TextBox.Resources>
                            <TextBox.Text>
                                <MultiBinding Converter="{StaticResource SchcolarFullNameConverter}">
                                    <Binding Path="Name" />
                                    <Binding Path="Surname" />
                                    <Binding Path="SecondName" />
                                </MultiBinding>
                            </TextBox.Text>
                        </TextBox>
 
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
    class ViewModel
    {
        public SchcolarModel SelectedSchcolar { get; set; }
        public ObservableCollection<SchcolarModel> Schcolars { get; }
        public ViewModel()
        {
            var range = Enumerable.Range(1, 100).Select(x => new SchcolarModel { Name = $"Name{x}", Surname = $"Surname{x*x}", SecondName = $"SecondName{x*x-x}" });
            Schcolars = new ObservableCollection<SchcolarModel>(range);
        }
    }
    class SchcolarModel
    {
        public string Name { get; set; }
        public string Surname { get; set; }
        public string SecondName { get; set; }
 
    }
    class SchcolarFullNameConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
            => values
            .Take(3)
            .Select(x => x.ToString())
            .Where(x => !string.IsNullOrWhiteSpace(x))
            .Aggregate(string.Empty, (s, x) => s += x.Trim() + " ")
            .Trim();
 
        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
            => value.ToString()
            .Split(new[] { ' ' }, 3, StringSplitOptions.RemoveEmptyEntries)
            .Concat(new[] { string.Empty, string.Empty, string.Empty })
            .Take(3)
            .ToArray();
    }


Вариант2:
через ViewModel

XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<Window x:Class="MS_TEXTBOX.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MS_TEXTBOX"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        Title="MainWindow"
        Width="525"
        Height="350">
    <Window.DataContext>
        <local:ViewModel />
    </Window.DataContext>
    <Grid>
        <ListBox Grid.Column="0"
                 ItemsSource="{Binding Schcolars}"
                 SelectedItem="{Binding SelectedSchcolar}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Margin="5">
                        <TextBox Text="{Binding FIO}" />
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class ViewModel
    {
        public SchcolarModel SelectedSchcolar { get; set; }
        public ObservableCollection<SchcolarViewModel> Schcolars { get; }
        public ViewModel()
        {
            var range = Enumerable.Range(1, 100).Select(x => new SchcolarViewModel(new SchcolarModel { Name = $"Name{x}", Surname = $"Surname{x*x}", SecondName = $"SecondName{x*x-x}" }));
            Schcolars = new ObservableCollection<SchcolarViewModel>(range);
        }
    }
    class SchcolarModel
    {
        public string Name { get; set; }
        public string Surname { get; set; }
        public string SecondName { get; set; }
 
    }
    class SchcolarViewModel
    {
        public SchcolarModel Schcolar { get; private set; }
        public SchcolarViewModel(SchcolarModel schcolar)
        {
            Schcolar = schcolar;
        }
        public string FIO
        {
            get { return $"{Schcolar.Name} {Schcolar.SecondName} {Schcolar.Surname}".Trim(); }
            set
            {
                var data = value.ToString()
                .Split(new[] { ' ' }, 3, StringSplitOptions.RemoveEmptyEntries)
                .Concat(new[] { string.Empty, string.Empty, string.Empty })
                .Take(3)
                .ToArray();
                Schcolar.Name = data[0];
                Schcolar.SecondName = data[1];
                Schcolar.Surname = data[2];
            }
        }
    }


П.С. Выбор вариантов зависит только от предпочтения и задач приложения

Добавлено через 4 минуты
П.С.С. В целом при желании логику конвертера можно перенести на уровень модели, но плюсов от этого мало - разве что кода чуть меньше
1
HF
1163 / 749 / 181
Регистрация: 09.09.2011
Сообщений: 2,314
Записей в блоге: 2
24.04.2017, 15:17 35
Спасибо skilllab и amarf за ответы. Последнее сообщение с реализацией подвердило догадку в том, что нужно переделать классы. В итоге переписал ViewModel классы и всё получилось.
0
24.04.2017, 15:17
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
24.04.2017, 15:17
Помогаю со студенческими работами здесь

Паттерн MVVM
Добрый день. Все началось с этой темы, где Storm23 дал мне немало ценных советов (за что ему...

Паттерн mvvm
Здравствуйте! Подскажите, пожалуйста, как реализовать паттерн mvvm на wpf? Читал разные статьи,...

Паттерн MVVM в WPF
Кто хорошо знает паттерн MVVM на WPF?

MVVM паттерн и привязка данных
Доброго времени суток! Относительно недавно начал изучать данный паттерн и технологию в целом. Не...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
35
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru