【问题标题】:Close Windows on TextBox text change using Mvvm, Wpf,C#,Visual Studio使用 Mvvm、Wpf、C#、Visual Studio 在 TextBox 文本更改上关闭 Windows
【发布时间】:2019-09-06 11:48:10
【问题描述】:

我想在 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;
    }
}

****************************** 编辑为答案 ****************** ********** ModelView 的变化:

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);

        }

【问题讨论】:

  • 作为解决方法,您可以默认关闭按钮不可见/禁用,并且仅当文本框中的文本满足您的条件时才启用它。不要忘记解雇propertychanged(目前你的Text属性没有它)
  • window参数是否可变?为什么不将窗口设置为视图模型中的属性,然后从设置器中的条件调用EndTestExitAction(Window window)
  • @PavelAnikhouski 我希望这个隐藏的按钮在正确的字符串到来时自动拍摄.. 有可能吗?
  • 没有什么反对使用 TextBox.TextChanged 事件来关闭您的窗口。另一方面,MVVM 中的所有内容都反对在 ViewModel 中引用您的 VIEW。 ViewModel 应该分开,它应该在没有 View 的情况下工作。如果您对当前的 ViewModel 进行单元测试,它将失败。
  • @NawedNabiZada MVVM 并不意味着将我的逻辑与我的观点分开?我在我的 ViewModel 中登录并在窗口中查看

标签: c# wpf mvvm


【解决方案1】:

使用 MVVM 有点困难,但您可以做的是在 ViewModel 中创建一个事件并附加一个函数,该函数将在您的视图后面的代码中关闭您的窗口。然后,您将能够在需要关闭窗口时在 ViewModel 中调用您的事件(或者在 View 中而不是在 ViewModel 中执行其他更方便的操作)

【讨论】:

    【解决方案2】:

    您几乎已经实现了所需的一切。您真正需要做的就是从您的 setter 调用 private void EndTestExitAction(Window window) 并在构造期间提供 window 其值:

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

    其中window 是您的视图模型的属性。

    【讨论】:

    • 不是 MVVM,不好的做法!
    • 这怎么不在 MVVM 中?视图通过视图模型设置文本,视图模型在自身内部调用一个作用于视图的方法。
    • ViewModel 对 View 一无所知...您应该将这些层分开。 View 知道 ViewModel,但 ViewModel 对视图一无所知
    • 我想你是对的,与 Presenter 混淆了。但是,如何通过 MVVM 关闭窗口呢?即使使用命令方法(目前通过按钮实现),视图模型也知道并控制绑定之外的视图。
    • 人们在谈到 MVVM 时犯的最大错误之一是他们认为不允许使用代码背后的代码。只要是视图逻辑,您仍然可以使用 Button.Click、TextBox.TextChanged 等代码或事件。任何带有模型逻辑的东西都应该通过带有绑定的 ViewModel
    【解决方案3】:

    从 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 && (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); }
    }
    

    关于我最近的blog post的更多详细信息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-05-13
      • 1970-01-01
      • 1970-01-01
      • 2018-10-22
      • 1970-01-01
      • 2010-09-06
      • 2013-06-07
      相关资源
      最近更新 更多