Форум программистов, компьютерный форум, киберфорум
C#: WPF, UWP и Silverlight
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.70/43: Рейтинг темы: голосов - 43, средняя оценка - 4.70
Модератор
 Аватар для TanaTiX
2939 / 1800 / 180
Регистрация: 19.02.2011
Сообщений: 6,556

Пытаюсь понять идеологию MVVM

25.02.2020, 19:51. Показов 10249. Ответов 123
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
По предыдущему опыту (не C#) активно использовал MVC. Теперь пытаюсь понять идеологию MVVM. Не могу четко придумать, где должен быть контроллер или его аналог. Сейчас сижу, "курю" мануалы, пытаюсь осознать...[/OFF]
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
25.02.2020, 19:51
Ответы с готовыми решениями:

Пытаюсь разобраться с WPF и MVVM и создать приложение
Всем доброе время суток и всех с праздником! Пытаюсь разобраться с WPF и MVVM Фаил MainWindow.xaml <Window...

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

Пытаюсь понять, не получается
По запросу - Магазины Ярославля 4-9 места занимают какие-то левые сайты, причем в описании присутствует название моего сайта - Магазины...

123
Модератор
 Аватар для TanaTiX
2939 / 1800 / 180
Регистрация: 19.02.2011
Сообщений: 6,556
07.04.2020, 15:02  [ТС]
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Когда вопросы по связи между Model и View будут прояснены, продолжим дорабатывать Модель.
Давай так. Хочется уже немного вьюхой заняться.
Когда будет перерыв - сделаю парочку набросков для реализации сохранения.
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Я это "приберегал" для реализации View.

Не по теме:

Я новичок в C#, но не в программировании. Тем не менее всегда есть чему учиться ;)


Жду следующих инструкций.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16165 / 11285 / 2892
Регистрация: 21.04.2018
Сообщений: 33,174
Записей в блоге: 2
07.04.2020, 15:14
Цитата Сообщение от TanaTiX Посмотреть сообщение
Жду следующих инструкций.
Тогда вопрос тот же.
Как вы видите интерфейс пользователя?
Но без статистики и сохранения/восстановления.
Только с учётом имеющихся возможностей Модели.
1
Модератор
 Аватар для TanaTiX
2939 / 1800 / 180
Регистрация: 19.02.2011
Сообщений: 6,556
07.04.2020, 15:18  [ТС]
Мы кнопочки оставим, но сделаем их не активными.
Что до продолжения сохраненной игры, то при наличии не завершенной покажем окошко, мол игра продолжена, игрок такой-то и такой-то, ход того-то.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16165 / 11285 / 2892
Регистрация: 21.04.2018
Сообщений: 33,174
Записей в блоге: 2
07.04.2020, 15:48
View у нас будет однооконной, но с различными визуальными состояниями.
Для каждого из этих состояний View будет свой UserControl и каждому из них надо сначала задать интерфейсы Контекста Данных.
Сами сможете их (интерфейсы) спроектировать?

Добавлено через 18 минут
Какие свойства VM нужны для исходного экрана?
  1. Команда для кнопки "Новая игра"
  2. Команда для кнопки "Настройки"
  3. Для статистики список ObservableCollection с типом для данных по пользователю. Значит надо создать соответсвующий тип данных для элемента коллекции
  4. Команда для кнопки "Восстановить игру"
  5. Команда для кнопки "Выйти"
Все эти члены объединяем в интерфейсе IMainVM

Экран настроек (ISettingVM):
  1. Команда для смены имени пользователя
  2. Команда для смены изображения крестика или нолика
  3. Изображение крестика
  4. Изображение нолика

Так же для всех остальных экранов.
1
Модератор
 Аватар для TanaTiX
2939 / 1800 / 180
Регистрация: 19.02.2011
Сообщений: 6,556
07.04.2020, 16:56  [ТС]
Переименовал User в UserTypes. Создал класс User для хранения информации о пользователях.
Создал вот такой класс
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
using System.Collections.ObjectModel;
using System.Windows.Input;
 
namespace Common
{
    public class IFirstScreen
    {
        ICommand CommandSrartNewGame;
        ICommand CommandRepairGame;
        ICommand CommandCancelGame;
        ICommand CommandShowSettings;
        ObservableCollection<User> users;//разве это должно быть в этом объекте?
 
    }
}
Я в правильном направлении двигаюсь?
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16165 / 11285 / 2892
Регистрация: 21.04.2018
Сообщений: 33,174
Записей в блоге: 2
07.04.2020, 17:58
Цитата Сообщение от TanaTiX Посмотреть сообщение
Я в правильном направлении двигаюсь?
Только маленькая ошибка.
Интерфейс рассчитан на использование с WPF View, поэтому все члены должны быть публичными свойствами
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
using System.Collections.ObjectModel;
using System.Windows.Input;
 
namespace Common
{
    public class IFirstScreen
    {
        ICommand CommandSrartNewGame {get;}
        ICommand CommandRepairGame {get;}
        ICommand CommandCancelGame {get;}
        ICommand CommandShowSettings {get;}
        ObservableCollection<User> Users {get;} //разве это должно быть в этом объекте?
 
    }
}
Цитата Сообщение от TanaTiX Посмотреть сообщение
//разве это должно быть в этом объекте?
Всё что нужно для этого экрана должно быть в этом интерфейсе.

Добавлено через 1 минуту
TanaTiX, и раз мы делаем ПРАВИЛЬНО, то возьмите за привычку сразу добавлять теги документации

Добавлено через 2 минуты
Ещё рекомендация по "Правилам именования".
В английском языке "главное" слово идёт последним:
CommandSrartNewGame -> SrartNewGameCommand
1
Модератор
 Аватар для TanaTiX
2939 / 1800 / 180
Регистрация: 19.02.2011
Сообщений: 6,556
07.04.2020, 18:15  [ТС]
Может что еще придумаю...
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
using System.Collections.ObjectModel;
using System.Windows.Input;
 
namespace Common
{
    public class IFirstScreenVM
    {
        ICommand SrartNewGameCommand { get; }
        ICommand RepairGameCommand { get; }
        ICommand CancelGameCommand { get; }
        ICommand ShowSettingsCommand { get; }
        ICommand ShowStatisticCommand { get; }
 
    }
}
C#
1
2
3
4
5
6
7
8
9
10
using System.Windows.Input;
 
namespace Common
{
    public class ISettingsVM
    {
        ICommand ChangeUserNameCommand { get; }
        ICommand ChangeUserPieceCommand { get; }
    }
}
C#
1
2
3
4
5
6
7
8
9
10
11
using System.Collections.ObjectModel;
using System.Windows.Input;
 
namespace Common
{
    public class IFirstScreen
    {
        ObservableCollection<User> users;
 
    }
}
C#
1
2
3
4
5
6
7
8
9
10
using System.Windows.Input;
 
namespace Common
{
    public class IGameVM
    {
        ICommand MoveCommand { get; }
        ICommand LoseCommand { get; }
    }
}
C#
1
2
3
4
5
6
7
8
9
10
using System.Windows.Input;
 
namespace Common
{
    public class IGameEndVM
    {
        ICommand ShowFirstScreenCommand { get; }
        ICommand RevengeCommand { get; }
    }
}
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16165 / 11285 / 2892
Регистрация: 21.04.2018
Сообщений: 33,174
Записей в блоге: 2
07.04.2020, 22:15
Цитата Сообщение от TanaTiX Посмотреть сообщение
IFirstScreenVM и IFirstScreen
Не надо разносить IFirstScreenVM и IFirstScreen
Мы будем указывать интерфейс в Контексте Данных UserControl. И сможем указать только один интерфейс.

Добавлено через 1 минуту
Цитата Сообщение от TanaTiX Посмотреть сообщение
public class ISettingsVM
Без комментов (тегов документации) не всё понятно.

ChangeUserPieceCommand что будет делать? Выбирать крестиками или ноликами играет?

Тогда нам сюда нужно свойство (коллекция) с типом в котором значения фишек (CellContent) и ссылка на их изображение (ImageSource)

Добавлено через 2 минуты
Цитата Сообщение от TanaTiX Посмотреть сообщение
public class IGameVM и IGameEndVM
Каким экран соответствуют?

Добавлено через 7 минут
Пропустил самое главное!Должны быть ИНТЕРФЕЙСЫ, а не классы
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System.Collections.ObjectModel;
using System.Windows.Input;
 
namespace Common
{
    /// <summary>Интерфейс ViewModel для начального экрана</summary>
    public interface IFirstScreenVM
    {
        /// <summary>Команда старта новой игры</summary>
        ICommand SrartNewGameCommand { get; }
        /// <summary>Команда востановления сохранённой игры</summary>
        ICommand RepairGameCommand { get; }
        /// <summary>Команда выхода из игры</summary>
        ICommand CancelGameCommand { get; }
        /// <summary>Команда перехода в настройки</summary>
        ICommand ShowSettingsCommand { get; }
        /// <summary>Команда перехода в статистику</summary>
        ICommand ShowStatisticCommand { get; } // Если у нас статистика на перовм экране, зачем эта команда?
        /// <summary>Список пользователей и их данные</summary>
        ObservableCollection<User> Users { get; }
    }
}


Добавлено через 3 часа 30 минут
TanaTiX, после всех корректировок получаем пять интерфейсов для пяти UserControl.

Создаём проект типа "Библитека пользовательских элементов управления WPF (Net Framework)"

В нём добавляем ссылку на общую библиотеку.

Создаём пять UserControl по одному для каждого экрана.
Те UC что не имеют данных (только команды) в контексте данных устанавливаем d:DataContext="{x:Type Интерфейс}"

Для тех интерфейсов у которых есть данные, сначала создаём Контекст Данных Времени Разработки.

Например для интерфейса
C#
1
2
3
4
5
6
7
8
9
    public interface IStatisticVM
    {
        /// <summary>Список игроков</summary>
        ObservableCollection<User> Users { get; }
 
        /// <summary>Вернуться на 1ю панель</summary>
        ICommand ExitStatisticCommand { get; }
 
    }
Делаем такой класс
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
    public class StatisticVM : IStatisticVM
    {
        public ObservableCollection<User> Users { get; }
         = new ObservableCollection<User>();
        public ICommand ExitStatisticCommand { get; }
 
        public StatisticVM()
        {
            Users.Add(new User() { Name = "Петя", Total = 10, Win = 5 });
            Users.Add(new User() { Name = "Ваня", Total = 15, Win = 7 });
            Users.Add(new User() { Name = "Катя", Total = 5, Win = 3 });
        }
    }
Добавлено через 3 минуты
Контекст данных для них подключаем так
XML
1
2
3
<d:UserControl>
   <local:StatisticVM/>
</d:UserControl>
1
Модератор
 Аватар для TanaTiX
2939 / 1800 / 180
Регистрация: 19.02.2011
Сообщений: 6,556
08.04.2020, 01:25  [ТС]
Форматирование контролов примерно таким должно быть?
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<UserControl x:Class="View.FirstScreenUC"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:View"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <d:UserControl d:DataContext="{x:Type IFirstScreenVM}">
        <local:FirstScreenVM/>
    </d:UserControl>
    <Grid>
        <Button>Просто кнопочка, что бы пусто не было )))</Button>
    </Grid>
</UserControl>
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16165 / 11285 / 2892
Регистрация: 21.04.2018
Сообщений: 33,174
Записей в блоге: 2
08.04.2020, 11:06
Цитата Сообщение от TanaTiX Посмотреть сообщение
Форматирование контролов примерно таким должно быть?
Разве ошибку на таком не выдаёт?
Вроде так должно быть
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<UserControl x:Class="View.FirstScreenUC"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:View"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <d:UserContro.DataContext>
        <local:FirstScreenVM/>
    </d:UserControl.DataContext>
    <Grid>
        <Button Command="{Binding СвойствоFirstScreenVM}">Просто кнопочка, что бы пусто не было )))</Button>
    </Grid>
</UserControl>
Добавлено через 29 минут
Если данных нет - только команды.
То можно временную VM не создавать.
И тогда будет так
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<UserControl x:Class="View.FirstScreenUC"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:View"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800"
             xmlns:comm="пространство имён общей библиотеки"
             d:DataContext="{x:Type comm:IFirstScreenVM}">
    <Grid>
        <Button Command="{Binding СвойствоFirstScreenVM}">Просто кнопочка, что бы пусто не было )))</Button>
    </Grid>
</UserControl>
Добавлено через 9 минут
При задании контекста данных начинает правильно работать конструктор привязок.
Можно задавать привязки через него - это уменьшит вероятность случайных ошиибок.

Так же все поля отображающие данные мы теперь видим заполненными и сразу в конструкторе можем оценить их и отловить ошибки неправильных привязок.
1
Модератор
 Аватар для TanaTiX
2939 / 1800 / 180
Регистрация: 19.02.2011
Сообщений: 6,556
08.04.2020, 12:06  [ТС]
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<UserControl x:Class="View.FirstScreenUC"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:View"
             mc:Ignorable="d" 
             xmlns:comm="clr-namespace:Common;assembly=Common"
             d:DataContext="{x:Type comm:IFirstScreenVM}"
             d:DesignHeight="450" d:DesignWidth="800">
    <!--<d:UserControl d:DataContext="{x:Type IFirstScreenVM}">
        <local:FirstScreenVM/>
    </d:UserControl>-->
    <Grid>
        <Button>Просто кнопочка, что бы пусто не было )))</Button>
    </Grid>
</UserControl>
Не удается найти указанный файл
Ошибка подчеркнута зеленым на строке d:DataContext="{x:Type comm:IFirstScreenVM}"

Добавлено через 4 минуты
В созданном проекте View создал папку Resources, там еще папка Images. Соответственно там изображения крестиков и ноликов. В проекте Common создал класс
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace Common
{
    public static class ImagesCollection
    {
        public static string Directoryn = @"/Images/";
        public static Dictionary<string, string> Pieces = new Dictionary<string, string>()
        {
            {"crossStandrart", @"cross.svg" },
            {"zeroStandrart", @"zero.svg" },
            {"crossYes", @"yes.svg" },
            {"zeroNo", @"no.svg" }
        };
        
    }
}
Сомневаюсь в правильности расположения и содержания.
0
Модератор
 Аватар для TanaTiX
2939 / 1800 / 180
Регистрация: 19.02.2011
Сообщений: 6,556
08.04.2020, 21:11  [ТС]
Создал пример визуального оформления статистики
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<UserControl x:Class="View.StatisticUC"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:View"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800"
             xmlns:comm="clr-namespace:Common;assembly=Common">
    <d:UserControl.DataContext>
        <local:StatisticVM />
    </d:UserControl.DataContext>
    <DataGrid ItemsSource="{Binding Users}">
        <DataGrid.Columns>
            <DataGridTextColumn Header="Игрок" Binding="{Binding Name}"/>
            <DataGridTextColumn Header="Игр" Binding="{Binding Total}"/>
            <DataGridTextColumn Header="Выигрышей" Binding="{Binding Win}"/>
            <DataGridTextColumn Header="Проигрышей" Binding="{Binding Lose}"/>
        </DataGrid.Columns>
    </DataGrid>
<Button Content="Закрыть статистику" Command="{Binding ExitStatisticCommand}" Height="auto"></Button>
</UserControl>
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
using Common;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
 
namespace View
{
    public class StatisticVM : IStatisticVM
    {
        public ObservableCollection<User> Users => new ObservableCollection<User> {
            new User(){ Name = "Иван", Total=111,  Win=56, Lose=5 },
            new User(){ Name = "Петр", Total=31,  Win=26, Lose=5 },
            new User(){ Name = "Сидор", Total=81,  Win=44, Lose=5 },
            new User(){ Name = "Феофан", Total=1000,  Win=777, Lose=5 },
            new User(){ Name = "Акакий", Total=9999,  Win=56, Lose=888 },
            new User(){ Name = "Ivengo", Total=564,  Win=564, Lose=0 }
        };
 
        public ICommand ExitStatisticCommand { get; }
    }
}
Визуального выглядит пока никак, но может доработаем. Я так понимаю, что на данном этапе нужен пример работы с данными.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16165 / 11285 / 2892
Регистрация: 21.04.2018
Сообщений: 33,174
Записей в блоге: 2
09.04.2020, 13:06
Цитата Сообщение от TanaTiX Посмотреть сообщение
Я так понимаю, что на данном этапе нужен пример работы с данными.
Хоть это и рано пока, но пройдём немного вперёд для понимания для чего это всё делается.

Для этого нам надо добавить в Решение два проекта:
ViewModel - Библиотека классов FW
AppWPF - Приложение WPF FW.


Нам надо задать навигатор для перемещения между экранами в одном окне.
Один из вариантов его создания.

Каждый экран это единственный в Окне UC.
Переключать экраны будем методом в App.
Чтобы в CB App было доступно наше единственное окно, в XAML убираем StartupUri и задаём обработчик Startup.
См. тему Ресурсы приложения и запуск основного окна из Code-Behind App [WPF, Элд Хасп]

В CB App создаём поле только для чтения и инициализируем его экземпляром Window задаём нужные параметры: размер по содержимому, позиция и т.д.

Так каждому экрану у нас сопоставлен интерфейс, то переключение между экранами можно сделать по типу полученного интерфейса.

Каждый экран у нас будет только в одном экземпляре.
Поэтому для каждого создаём поле только для чтения с экземпляром UC.

Задаём метод принимающий Type type
В теле метода проверяем какой это интерфейс и записываем нужный UC в свойство Content Окна.

Всё наш простенький навигатор готов.

Теперь надо передать его в VM.

Но её у нас пока нет...

Начинаем её создавать.

Добавлено через 18 минут
Создавать VM будем в несколько шагов.

Для начала добавим в общую библиотеку базовые классы отсюда:
Новая реализация OnPropertyChangedClass [WPF, Элд Хасп]
Новая реализация RelayCommand с исправлениями от proa33 и kolorotur [WPF, Элд Хасп]

В проекте VM для начала создадим класс реализующий все интерфейсы.
Он будет производным от OnPropertyChangedClass и через запятую надо указать все интерфейсы.
Потом на каждом интерфейсе в "быстрых решениях" выбрать "Реализовать интерфейс".

Получим "рыбу" которою надо доделать.

Все свойства реализуем по такому подобию
C#
1
2
private string _text;
public string Text {get=>_text; set=>SetProperty(ref _text, value);}
Добавляем конструктор без параметров.
Этот конструктор будет использоваться только для Режима Разработки.
В данном случае он нам не нужен - у нас всё это уже сделано в View.
Поэтому оставляем его пустым.

Добавляем второй конструктор принимающий делегат метода навигатора в типе Action<Type>.
Делегат метода сохраняем в поле только для чтения.
Все команды для навигации инициализируем экземплярам RelayCommand. В исполнительный метод команды передаём вызов делегата навигатора с нужным типом интерфейса.

Пока на этом с VM приостановим.

Добавлено через 9 секунд
Создавать VM будем в несколько шагов.

Для начала добавим в общую библиотеку базовые классы отсюда:
Новая реализация OnPropertyChangedClass [WPF, Элд Хасп]
Новая реализация RelayCommand с исправлениями от proa33 и kolorotur [WPF, Элд Хасп]

В проекте VM для начала создадим класс реализующий все интерфейсы.
Он будет производным от OnPropertyChangedClass и через запятую надо указать все интерфейсы.
Потом на каждом интерфейсе в "быстрых решениях" выбрать "Реализовать интерфейс".

Получим "рыбу" которою надо доделать.

Все свойства реализуем по такому подобию
C#
1
2
private string _text;
public string Text {get=>_text; protected set=>SetProperty(ref _text, value);}
Добавляем конструктор без параметров.
Этот конструктор будет использоваться только для Режима Разработки.
В данном случае он нам не нужен - у нас всё это уже сделано в View.
Поэтому оставляем его пустым.

Добавляем второй конструктор принимающий делегат метода навигатора в типе Action<Type>.
Делегат метода сохраняем в поле только для чтения.
Все команды для навигации инициализируем экземплярами RelayCommand. В исполнительный метод команды передаём вызов делегата навигатора с нужным типом интерфейса.

Пока на этом с VM приостановим.

Добавлено через 5 минут
Теперь переходим к созданию VM в App.
Делается это очень просто.
В методе обработчика Startup прописываем создание экземпляра VM с передачей в конструктор метода навигатора.
Этот экземпляр VM записываем в DataContext окна.
И показываем окно.

После этого можно делать пробный запуск приложения.

Пока всё.
Дальше после реализации всего этого..

Добавлено через 1 минуту
Забыл!
Перед показом окна надо вызвать метод навигатора с интерфейсам первого экрана.
1
Модератор
 Аватар для TanaTiX
2939 / 1800 / 180
Регистрация: 19.02.2011
Сообщений: 6,556
10.04.2020, 17:20  [ТС]
По мере погружения в xaml появился вопрос. Как в наших "окнах" использовать DataTemplate? Сам факт добавления тега вызывает ошибку, мол свойство Content используется более одного раза.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16165 / 11285 / 2892
Регистрация: 21.04.2018
Сообщений: 33,174
Записей в блоге: 2
10.04.2020, 17:25
Цитата Сообщение от TanaTiX Посмотреть сообщение
Как в наших "окнах" использовать DataTemplate?
DataTemplate - это шаблон, а не UI элемент.
Его экземпляр создаётся либо в ресурсе, либо в свойстве принимающим такой тип.

Но где конкретно, в разрезе нашей задачи, вы собираетесь его применить?
У нас же там нет ни одного пользовательского окна.
1
Модератор
 Аватар для TanaTiX
2939 / 1800 / 180
Регистрация: 19.02.2011
Сообщений: 6,556
10.04.2020, 17:36  [ТС]
В настройках, мне подумалось, одного пользователя все же мало. Поэтому хочу создать 2 однотипных элемента для каждого из пользователей. Естественно под это все будут доработаны и модели, и интерфейсы.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16165 / 11285 / 2892
Регистрация: 21.04.2018
Сообщений: 33,174
Записей в блоге: 2
10.04.2020, 17:40
Цитата Сообщение от TanaTiX Посмотреть сообщение
В настройках...
Тогда шаблон надо задать в ресурсах контрола
XML
1
2
3
4
5
<UserControl.Resources>
       <DataTemplate TargetType={x:Type ....} x:Key=".....">
             .........
       </DataTemplate>
</UserControl.Resources>
И потом в свойстве где надо применить этот шаблон дать ссылку на этот ключ
1
Модератор
 Аватар для TanaTiX
2939 / 1800 / 180
Регистрация: 19.02.2011
Сообщений: 6,556
13.04.2020, 15:24  [ТС]
Пока концентрирую свое внимание на вью-части настроек.
Пока готово это:
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
<UserControl x:Class="View.SettingsUC"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:View"
             xmlns:comm="clr-namespace:Common;assembly=Common"
             DataContext="{x:Type comm:ISettingsVM}"
             mc:Ignorable="d"
             d:DesignHeight="700" d:DesignWidth="600">
    
    
        
            
            
    <UserControl.Resources>
        <local:BoolToVisibilityConverter x:Key="InputToVisibility"/>
        <Style TargetType="{x:Type TextBox}" x:Key="PropmptingTextBox">
            <Setter Property="BorderBrush" Value="Black"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type TextBox}">
                        <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
                            <Grid>
                                <TextBlock TextAlignment="Center" Text="Ваше имя...">
                                    <TextBlock.Visibility>
                                        <MultiBinding Converter="{StaticResource InputToVisibility}">
                                            <Binding ElementName="inputText" Path="IsFocused"/>
                                            <Binding ElementName="inputText" Path="Text"/>
                                        </MultiBinding>
                                    </TextBlock.Visibility>
                                </TextBlock>
                                <TextBox x:Name="inputText" TextAlignment="Center" Background="Transparent"/>
                            </Grid>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
 
        <DataTemplate x:Key="UserSettings" DataType="{x:Type local:SettingsUC}" x:Name="test">
 
 
            <DataGridCell Background="#c0c0c0">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="auto"></RowDefinition>
                        <RowDefinition Height="auto"></RowDefinition>
                        <RowDefinition></RowDefinition>
                        <RowDefinition Height="auto"></RowDefinition>
                    </Grid.RowDefinitions>
                    
                    <TextBox Grid.Row="0" FontWeight="Bold" FontSize="40" Style="{StaticResource PropmptingTextBox}"/>
                    <Button Grid.Row="1">
                        <Image  Source="Resources\Images\arrow.png"/>
                    </Button>
                    <ListBox Grid.Row="2" HorizontalContentAlignment="Center" ScrollViewer.VerticalScrollBarVisibility="Disabled">
                        <Image Margin="0, 63, 0, 63" Width="200" Height="200" Source="Resources\Images\cross.png"></Image>
                        <Image Margin="0, 63, 0, 63" Width="200" Height="200" Source="Resources\Images\no.png"></Image>
                        <Image Margin="0, 63, 0, 63" Width="200" Height="200" Source="Resources\Images\yes.png"></Image>
                        <Image Margin="0, 63, 0, 63" Width="200" Height="200" Source="Resources\Images\zero.png"></Image>
                    </ListBox>
                    <Button Grid.Row="3">
                        <Image Source="Resources\Images\arrow.png">
                            <Image.LayoutTransform>
                                <RotateTransform Angle="180"/>
                            </Image.LayoutTransform>
                        </Image>
                    </Button>
                </Grid>
                
                
            </DataGridCell>
        </DataTemplate>
    </UserControl.Resources>
    
    
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="40"></RowDefinition>
            <RowDefinition Height="auto"></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition Height="40"></RowDefinition>
        </Grid.RowDefinitions>
        <TextBlock Grid.Row="0" Background="Gold" HorizontalAlignment="Stretch" TextAlignment="Center" Height="auto">Настройки</TextBlock>
        <StackPanel Grid.Row="1" Orientation="Horizontal" Width="600"><!--Хорошо бы переделать-->
            <Label Width="300" Background="AliceBlue" HorizontalContentAlignment="Center" Content="Пользователь № 1"></Label>
            <Label Width="300" Background="AliceBlue" HorizontalContentAlignment="Center" Content="Пользователь № 2"></Label>
        </StackPanel>
        <Grid Grid.Row="2">
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <DataGridCell Grid.Column="0" ContentTemplate="{StaticResource ResourceKey=UserSettings}"/>
            <DataGridCell Grid.Column="1" ContentTemplate="{StaticResource ResourceKey=UserSettings}"/>
            <!--<Grid.ColumnDefinitions>
                <ColumnDefinition Width="auto"/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="40"/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <Label Grid.Row="0" Grid.Column="0" Background="DarkSeaGreen" VerticalContentAlignment="Center">Имя:</Label>
            <TextBox Grid.Row="0" Grid.Column="1" VerticalContentAlignment="Center" HorizontalContentAlignment="Center">Это поле должно быть заполнено</TextBox>
            
            <Label Grid.Row="1" Grid.Column="0" Background="DarkSeaGreen" VerticalContentAlignment="Center">Фишка:</Label>
            <ListBox Grid.Row="1" Grid.Column="1" SelectionMode="Single"></ListBox>-->
        </Grid>
        <Button Grid.Row="3" Command="{Binding ExitSettingsCommand}">Сохранить настройки и выйти</Button>
 
    </Grid>
</UserControl>
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
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
 
namespace View
{
    public class BoolToVisibilityConverter : IMultiValueConverter
    {
        /// <summary>
        /// Проверка на наличие фокуса и наличие текста в текстовом поле на основе стандартных параметров интерфейса IMultiValueConverter
        /// </summary>
        /// <param name="values"></param>
        /// <param name="targetType"></param>
        /// <param name="parameter"></param>
        /// <param name="culture"></param>
        /// <returns>true/false</returns>
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            bool hasFocus = (bool)values[0];
            bool hasText = !string.IsNullOrEmpty((string)values[1]);
            return (hasText || hasFocus) ? Visibility.Collapsed : Visibility.Visible;
        }
 
        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}
Все залито на гитхаб.
Но есть вопросы. Как избавиться от выделения рамкой DataGridCell?
Как настроить поведения кнопок для перелистывания списка только по одной штуке? А в идеале и зациклить, т.е. что бы после последнего элемента шел нулевой.
Как подправить верстку, что бы избавиться от жестко заданных значений.
Была еще идея через свойство менять часть шаблона (заголовок), но было принято решение просто оформить парочку текстовых полей вне шаблона. Если у кого-то будут мысли, то с удовольствием послушаю, если нет - не критично.

P.S. Дизайн пока так себе, но как я понимаю, прелесть подхода в том, что его можно поменять когда угодно. Но "верстка" меняться не планируется.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16165 / 11285 / 2892
Регистрация: 21.04.2018
Сообщений: 33,174
Записей в блоге: 2
13.04.2020, 22:35
Цитата Сообщение от TanaTiX Посмотреть сообщение
Но есть вопросы. Как избавиться от выделения рамкой DataGridCell?
Так как у вас нет DataGrid, то не должно быть и DataGridCell.
Зачем вы его вообще всунули в шаблон?
От там висит порожняком.

Добавлено через 3 минуты
Цитата Сообщение от TanaTiX Посмотреть сообщение
XML
58
59
60
61
62
63
                    <ListBox Grid.Row="2" HorizontalContentAlignment="Center" ScrollViewer.VerticalScrollBarVisibility="Disabled">
                        <Image Margin="0, 63, 0, 63" Width="200" Height="200" Source="Resources\Images\cross.png"></Image>
                        <Image Margin="0, 63, 0, 63" Width="200" Height="200" Source="Resources\Images\no.png"></Image>
                        <Image Margin="0, 63, 0, 63" Width="200" Height="200" Source="Resources\Images\yes.png"></Image>
                        <Image Margin="0, 63, 0, 63" Width="200" Height="200" Source="Resources\Images\zero.png"></Image>
                    </ListBox>
А как вы собираетесь менять рисунки?
Под каждое изменение заново компилировать программу?
Раз есть список рисунков, View его должна получить от VM.
А VM от App.
App может получить его из настроек приложения.

Добавлено через 56 секунд
Раз Контролу нужны данные, а их нет в интерфейсе, то надо дополнить интерфейс этими данными.

Добавлено через 6 минут
Цитата Сообщение от TanaTiX Посмотреть сообщение
Как настроить поведения кнопок для перелистывания списка только по одной штуке? А в идеале и зациклить, т.е. что бы после последнего элемента шел нулевой.
В данном случае, мне кажет проще всего сделать ещё UC для этой области.
Конектится он будет на свой интерфейс.
Это интерфейс будет базовым для интерфейса настроек.
В самом интерфейсе будет только одно свойство - список картинок в типе ImageSource.
В само UС два дополнительных свойства: индекс картинки и индекс залоченной картинки (та которую надо пропускать).
Кнопки делают инкремент/декремент индекса по модулю длины коллекции.

Добавлено через 2 минуты
TanaTiX, можно будет в этом контроле добавить анимацию "пролистывания" картинок.
0
Модератор
 Аватар для TanaTiX
2939 / 1800 / 180
Регистрация: 19.02.2011
Сообщений: 6,556
13.05.2020, 13:11  [ТС]
Итак, что произошло за это время. Необходимо немного оживить тему.
Был допилен тестовый "дизайн" (в кавычках потому что дизайном это назвать сложно) - тут речь про WPF и тестовые данные (в т.ч. с перфиксом d). Затем (а точнее параллельно) создана вьюмодель, снабжающая данными вью. В дальнейшем она перестроена на обмен данными между моделью и вью (INPC). На данный момент отладка приложения. Добавлен способ сохранения прерванной игры (в xml).
Помимо этого использовали очень интересный, мощный и гибкий инструмент AttachedProperty (класс AProperty) - с его помощью реализовано "квадратное" поведение объектов, т.е. когда ширина равняется длине не зависимо от размера элемента.
Таким образом есть связка от модели до вью.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
13.05.2020, 13:11

Основы MVC, пытаюсь понять код
Суть в чем, мне на производственной практике дали задание написать веб-приложение для управления списком сотрудников компании. Ну я его...

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

Пытаюсь понять шаблонизатор Handlebars для JavaScript
Привет. Нагуглил вот эту статью: http://getinstance.info/articles/tools/introduction-to-handlebars/ Но у меня самый первый пример...

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

Написать программу в Excel, пытаюсь понять, но не получается
Написать программу сведений о выпускниках университета. Структура исходных данных: шифр студента, фамилия, имя, отчество, год окончания...


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

Или воспользуйтесь поиском по форуму:
60
Ответ Создать тему
Новые блоги и статьи
мат медиц модель 30. презентация проекта
anaschu 27.08.2026
хоп хоп хоп хидахоп, а я кладую))
Как у меня протекала болезнь
zorxor 27.08.2026
Здравствуйте, друзья! Эта запись блога предназначена именно для вас - для моих дорогих друзей, которые знали меня лично. Чтобы ответить на вопрос - а что же со мной произошло на самом деле? Я учился. . .
Нашел вот забавное видео о измерениях. Лучшее что я видел на эту тему
kumehtar 26.08.2026
ILETXiw9bMQ Основная суть и тезисы по измерениям: 0D (Нулевое измерение): точка, не имеющая длины, ширины, высоты или объема. Объект не может перемещаться в 0D. 1D (Первое измерение):. . .
[EasyBuilder Pro] Памятка по разработке для панелей Weintek
ФедосеевПавел 26.08.2026
Памятка по разработке для панелей Weintek ВВЕДЕНИЕ Ранее, при реализации проектов основное внимание уделял разработке управляющей программы для контроллера, а панели оператора доставалось время. . .
Модель по догадкам
anaschu 25.08.2026
Прошло две недели. Я уже рассказывал, как разговаривал с сотрудниками у сортировки и как понял, что главная ветка — не про приёмку, а про отбор. Но тогда я думал, что понял механику. На этой неделе я. . .
Запись в регистр сведений независимо от заполненности табличной части
Maks 25.08.2026
Реализация из решения ниже выполнена на нетиповом документе с несколькими табличными частями, разработанного в КА2. Задача: Обеспечить запись документа в регистр сведений независимо от. . .
Ноутбук Альфария
kumehtar 24.08.2026
Встретился тут в сети ноутбук Альфария, примарха Альфа-Легиона. Хотя возможно, это ноутбук Омегона, разумеется. Ну как вам?
Мастера простых решений
DevAlt 23.08.2026
В сишарп стэках winforms, да и wpf существует сложная система связывания источниках данных и элементов формы(текстовые поля и метки), опирается все это на технологию событий и мета. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru