Форум программистов, компьютерный форум, киберфорум
Наши страницы
C#: WPF, UWP и Silverlight
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.60/5: Рейтинг темы: голосов - 5, средняя оценка - 4.60
Lexeq
1013 / 664 / 456
Регистрация: 21.01.2014
Сообщений: 1,769
Завершенные тесты: 2
1

Валидация и закрытие окна

10.11.2019, 22:22. Просмотров 912. Ответов 5
Метки mvvm (Все метки)

Хочу сделать простую вещь - по нажатию кнопки происходит валидация введенных данных (к кнопке привязана комманда с методом валидации), и если ошибок нет, то закрыть окно. С реализацией валидации проблем нет (ВМ реализует INotifyDataError). А вот с как прикрутить закрытие окна идей нет. Я знаю, что можно проводить валидацию сразу при вводе данных и привязать CanExecute к свойству HasError, но из эстетических соображений хочется сделать по клику кнопки. Есть еще вариант биндить в xaml'e команду к св-ву Tag и в событии клика вручную вызывать команду и проверять результат, но это выглядит как-то костыльно. Есть у кого идеи как такое реализовать?
0
Лучшие ответы (1)
QA
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
10.11.2019, 22:22
Ответы с готовыми решениями:

Закрытие окна
this.DialogResult = (MessageBox.Show("Вы действительно хотите выйти из приложения", "DECBA",...

Закрытие окна.
Я знаю как убить процесс окна. Вот только незнаю как его закрыть. В WinApi накопал метод...

5

Felix Felicis
5 / 4 / 2
Регистрация: 31.05.2015
Сообщений: 154
10.11.2019, 23:06 2
Сам только что хотел задать вопрос про закрытие окна. Так что вопрос в двойне интересен.
0
Defences
169 / 113 / 36
Регистрация: 28.12.2016
Сообщений: 584
Завершенные тесты: 3
11.11.2019, 00:08 3
Lexeq, меня конечно Эдл Хасп обольет помоями за этот ответ, но я не вижу ничего противоречивого передать в параметрах окно и вызвать Close метод в VM

Добавлено через 3 минуты
Более правильное решение через атач, но я лично не люблю атач свойства и не рекомендую их использовать.

XML
1
2
3
<Window ...
        xmlns:xc="clr-namespace:ExCastle.Wpf"
        xc:DialogCloser.DialogResult="{Binding DialogResult}">
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
using System.Windows;
 
namespace ExCastle.Wpf
{
    public static class DialogCloser
    {
        public static readonly DependencyProperty DialogResultProperty =
            DependencyProperty.RegisterAttached(
                "DialogResult",
                typeof(bool?),
                typeof(DialogCloser),
                new PropertyMetadata(DialogResultChanged));
 
        private static void DialogResultChanged(
            DependencyObject d,
            DependencyPropertyChangedEventArgs e)
        {
            var window = d as Window;
            if (window != null)
                window.DialogResult = e.NewValue as bool?;
        }
        public static void SetDialogResult(Window target, bool? value)
        {
            target.SetValue(DialogResultProperty, value);
        }
    }
}
1
sttrox
24 / 22 / 5
Регистрация: 20.02.2018
Сообщений: 54
Завершенные тесты: 1
11.11.2019, 01:37 4
Lexeq и Felix Felicis, есть более интересное и простое и решение чем использование булевого флага. Честно говоря решение более-менее рабочее, но флаг использовать, это как шаг назад, нам дана абстракция, события, а мы возвращаемся к флагу. Как в работе с Win32, не хватает только указателей

Решение. В ваших VM создаёте событие
C#
1
public event EventHandler<bool> EventClose;
После чего убираете в App.xaml
XML
1
UriStartup="MainWindow.xaml"
Переходите в App.xaml.cs, в нём переопределяет OnStartup

C#
1
2
3
4
5
var window = new MainWindow();
var viewModel = new SomeViewModel();
viewModel.EventClose+= (o, e) => {if(e.NewValue.Equel(true))window.Close()};
window.DataContext=viewModel;
window.ShowDialog();
Код'а и операций не меньше?
За то у вас есть полный контроль над запуском приложения, что очень сильно пригодиться в будущих разработка. К примеру Вы в этой области можете загружать настройки приложения, в это время показывать заставку, а когда загрузятся настройки показываете главную View.

Не забывайте прописывать в ваших View
XML
1
d:DataContext="{d:DataInstance Type={x:Type SomeViewModel}}"
Так вам будет проще оперировать свойствами ViewModel'и
1
Элд Хасп
Модератор
4013 / 2753 / 878
Регистрация: 21.04.2018
Сообщений: 8,756
Записей в блоге: 2
11.11.2019, 06:31 5
Defences???
Дожил - мною уже пугать начали!


Если же реализовывать без нарушений MVVM, то конечно ViewModel сама не может обращаться к View.
По сути VM не обладает знанием о том даже какого типа View и тем более о том какие есть у неё методы.

Вариантов реализаций несколько.
В том числе и показанный вами, и предложенный sttrox.
Есть вариант с привязкой видимости окна к свойству VM.
Надо поискать в разделе пример такой реализации.

Добавлено через 11 минут
Lexeq, Felix Felicis, посмотрите тему Window.Visibility
Я там разбирался с тем как биндить видимость окна.
1
novikov.ea
1418 / 1026 / 352
Регистрация: 10.06.2011
Сообщений: 1,785
11.11.2019, 16:28 6
Лучший ответ Сообщение было отмечено Элд Хасп как решение

Решение

Цитата Сообщение от Lexeq Посмотреть сообщение
если ошибок нет, то закрыть окно
Данная задача соответствует шаблону "Во ViewModel что-то произошло - View должно как-то отреагировать". Задача типично решается с помощью TriggerAction'а:
1) Во ViewModel создаём событие и инициируем его в нужном месте
Абстрактное описание ViewModel
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class ViewModel
{
    public event EventHandler ValidationCompleted;
    
    protected void RaiseValidationCompleted()
    {
        ValidationCompleted?.Invoke(this, EventArgs.Empty);
    }
    
    private void Validate()
    {
        bool isOk = _validator.Validate(this);
        if (isOk)
        {
            RaiseValidationCompleted();
        }
    }
}

2) Создаём TriggerAction, который будет закрывать окно
Класс CloseWindowTriggerAction
C#
1
2
3
4
5
6
7
public class CloseWindowTriggerAction : TriggerAction<Window>
{
    protected override void Invoke(object parameter)
    {
        AssociatedObject.Close();
    }
}

3) Во View в XAML прописываем EventTrigger, связывая событие во ViewModel и написанный TriggerAction
Абстрактное описание кода окна
XML
1
2
3
4
5
6
7
<Window>
    <i:Interaction.Triggers>
        <i:EventTrigger SourceObject="{Binding DataContext, Mode=OneWay}" EventName="ValidationCompleted">
            <CloseWindowTriggerAction />
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Window>

Получается цепочка:
1) ViewModel вызывает событие
2) EventTrigger его получает и вызывает TriggerAction
3) TriggerAction выполняет действие над View

P.S. EventTrigger должен быть из пространства имён System.Windows.Interactivity, а не System.Windows
4
11.11.2019, 16:28
Answers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
11.11.2019, 16:28

Закрытие окна из другого файла
Имеются два окна, LoginRegisterWindow и MainWindow. В LoginRegisterWindow есть ContentControl в...

Минимизация и закрытие основного окна вместе с диалоговым
Всем добрый день. Нужно сделать, чтобы основное окно минимизировалось и закрывалось вместе с...

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

Или воспользуйтесь поиском по форуму:

6
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.