Закройте окна при изменении текста текстового поля с помощью Mvvm, Wpf, C #, Visual Studio

#c# #wpf #mvvm

#c# #wpf #mvvm

Вопрос:

Я хочу выполнить метод для события TextChange и для определенного текста, я хочу что-то сделать и закрыть окно с помощью MVVM

например, в этой части моего кода я хочу закрыть свое окно:

 if (text.Equals("12345"))
{
   //Exit from window
}
 

Я знаю, как я могу сделать это с помощью кнопки, используя команду, как у меня есть в коде следующего примера.

Но как я могу передать окно запущенному свойству, которое привязывается к тексту текстового поля?

или есть другой способ закрыть форму?

Я хочу сделать это в ViewModel, а не в исходном коде, чтобы написать свой код как шаблон MVVM, близкий к тому, что я могу

мой код XAML :

 <Window x:Class="PulserTesterMultipleHeads.UserControls.TestWindows"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:PulserTesterMultipleHeads.UserControls"
        mc:Ignorable="d"
        Name="MainTestWindow"
        Title="TestWindows" Height="450" Width="800">
    <Grid>
        <StackPanel>

            <TextBox Text="{Binding Text,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"></TextBox>

            <Button Command="{Binding EndTestExit}"
                    CommandParameter="{Binding ElementName=MainTestWindow}">Exit</Button>
        </StackPanel>
    </Grid>
</Window>
 

код, лежащий в основе XAML :

 using PulserTesterMultipleHeads.Classes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace PulserTesterMultipleHeads.UserControls
{
    /// <summary>
    /// Interaction logic for TestWindows.xaml
    /// </summary>
    public partial class TestWindows : Window
    {
        public TestWindows()
        {
            InitializeComponent();
            DataContext = new TestWindowsMV();
        }
    }
}
 

Просмотр кода модели :

 using PulserTester.ViewModel.Base;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;

namespace PulserTesterMultipleHeads.Classes
{
    public class TestWindowsMV : INotifyPropertyChanged
    {
        private string text;
        public string Text {
            get {
                return text;
            } set {
                text = value;
                if (text.Equals("12345"))
                {
                    //Exit from window
                }

            }
        }


        /// <summary>
        ///  for the example
        /// </summary>
        private ICommand _EndTestExit;

        public ICommand EndTestExit
        {
            get
            {
                if (_EndTestExit == null)
                {
                    _EndTestExit = new GenericRelayCommand<Window>((window) => EndTestExitAction(window));
                }
                return _EndTestExit;
            }
        }

        private void EndTestExitAction(Window window)
        {
            window.Close();
        }


        public event PropertyChangedEventHandler PropertyChanged;
    }
}
 

************************* Редактировать в качестве ответа ****************************
Изменение в представлении модели :

 public string Text {
            get {
                return text;
            } set {
                text = value;
                if (text.Equals("12345"))
                {
                    CloseAction();
                }

            }
        }
 

Изменения в коде, лежащие в основе:

 public TestWindows()
        {
            InitializeComponent();
            DataContext = new TestWindowsMV();

            if (((TestWindowsMV)DataContext).CloseAction == null)
                ((TestWindowsMV)DataContext).CloseAction = new Action(this.Close);

        }
 

Комментарии:

1. В качестве обходного пути вы можете сделать кнопку закрытия невидимой / отключенной по умолчанию и включить ее только тогда, когда текст в текстовом поле соответствует вашему условию. Не забудьте открыть огонь propertychanged (в настоящее время в вашей Text собственности его нет).

2. Является ли параметр window переменным? Почему бы вам не установить window как свойство в вашей модели представления и просто вызвать EndTestExitAction(Window window) из условного в вашем установщике?

3. @PavelAnikhouski Я хочу, чтобы эта скрытая кнопка срабатывала автоматически при появлении нужной строки.. это возможно?

4. Нет ничего против использования события TextBox.TextChanged для закрытия вашего окна. С другой стороны, все в MVVM против того, чтобы ссылаться на ваше ПРЕДСТАВЛЕНИЕ в ViewModel. ViewModel должен быть разделен, и он должен работать без представления. Если вы проведете модульное тестирование своей текущей модели представления, оно завершится неудачей.

5. @NawedNabiZada MVVM не означает отделить мою логику от моей точки зрения? У меня есть логин в моей ViewModel и просмотр в окне

Ответ №1:

Это довольно сложно с MVVM, но что вы можете сделать, так это создать событие внутри вашей ViewModel и прикрепить функцию, которая закроет ваше окно в коде позади вашего представления. Тогда вы сможете вызывать свое событие внутри ViewModel всякий раз, когда вам нужно закрыть окно (или сделать что-то еще, что удобнее делать в View, а не в ViewModel)

Ответ №2:

Самый простой способ закрыть представление из ViewModel — использовать прикрепленное свойство

 public static class perWindowHelper
{
    public static readonly DependencyProperty CloseWindowProperty = DependencyProperty.RegisterAttached(
        "CloseWindow",
        typeof(bool?),
        typeof(perWindowHelper),
        new PropertyMetadata(null, OnCloseWindowChanged));

    private static void OnCloseWindowChanged(DependencyObject target, DependencyPropertyChangedEventArgs args)
    {
        if (!(target is Window view))
            return;

        if (view.IsModal())
            view.DialogResult = args.NewValue as bool?;
        else
            view.Close();
    }

    public static void SetCloseWindow(Window target, bool? value)
    {
        target.SetValue(CloseWindowProperty, value);
    }


    public static bool IsModal(this Window window)
    {
        var fieldInfo = typeof(Window).GetField("_showingAsDialog", BindingFlags.Instance | BindingFlags.NonPublic);
        return fieldInfo != null amp;amp; (bool)fieldInfo.GetValue(window);
    }
}
 

который затем можно привязать к соответствующему свойству в вашей ViewModel

 <Window
    x:Class="...

    vhelp:perWindowHelper.CloseWindow="{Binding ViewClosed}">



private bool? _viewClosed;
public bool? ViewClosed
{
    get { return _viewClosed; }
    set { Set(nameof(ViewClosed), ref _viewClosed, value); }
}
 

Подробнее о моем недавнем сообщении в блоге.

Ответ №3:

У вас уже есть почти все, что вам нужно. Все, что вам действительно нужно сделать, это вызвать private void EndTestExitAction(Window window) из вашего установщика и указать window его значение во время построения:

 public string Text {
            get {
                return text;
            } set {
                text = value;
                if (text.Equals("12345"))
                {
                    EndTestExitAction(window)
                }

            }
        }
 

где window — свойство вашей модели представления.

Комментарии:

1. Не MVVM, плохая практика!

2. Как это не в MVVM? Представление задает текст через модель представления, модель представления вызывает внутри себя метод, который воздействует на представление.

3. ViewModel ничего не знает о представлении… Вы должны разделить эти слои. View знает ViiewModel, но ViewModel ничего не знает о представлении

4. Я полагаю, вы правы в этом, перепутали с Presenter. Но все же, как тогда закрыть окно через MVVM? Даже при использовании командного подхода (в настоящее время реализованного с помощью кнопки) модель представления знает и управляет представлением вне привязки.

5. Одна из самых больших ошибок, которые люди совершают, когда речь заходит о MVVM, заключается в том, что они думают, что исходный код недопустим. Вы все равно можете использовать код или события, такие как Button.Click, TextBox.TextChanged, если это логика просмотра. Все, что связано с логикой модели, должно проходить через ViewModel с привязками