小编典典

从ViewModel关闭窗口

c#

我使用创建了一个Login,window control以允许用户登录到WPF我正在创建的应用程序。

到目前为止,我已经创建了一个检查用户是否已经在为正确的凭据进入了一个方法username,并passwordtextbox登录屏幕,上binding2
properties

我是通过创建一个bool像这样的方法来实现的;

public bool CheckLogin()
{
    var user = context.Users.Where(i => i.Username == this.Username).SingleOrDefault();

    if (user == null)
    {
        MessageBox.Show("Unable to Login, incorrect credentials.");
        return false;
    }
    else if (this.Username == user.Username || this.Password.ToString() == user.Password)
    {
        MessageBox.Show("Welcome " + user.Username + ", you have successfully logged in.");

        return true;
    }
    else
    {
        MessageBox.Show("Unable to Login, incorrect credentials.");
        return false;
    }
}

public ICommand ShowLoginCommand
{
    get
    {
        if (this.showLoginCommand == null)
        {
            this.showLoginCommand = new RelayCommand(this.LoginExecute, null);
        }
        return this.showLoginCommand;
    }
}

private void LoginExecute()
{
    this.CheckLogin();
}

我也有一个commandbind对我的按钮之类的xaml东西;

<Button Name="btnLogin" IsDefault="True" Content="Login" Command="{Binding ShowLoginCommand}" />

当我输入用户名和密码时,它会执行适当的代码,无论是对还是错。但是,当用户名和密码均正确时,如何从ViewModel中关闭此窗口?

我以前尝试过使用a,dialog modal但效果不佳。此外,在我的app.xaml中,我做了如下操作,首先加载登录页面,然后为true,则加载实际的应用程序。

private void ApplicationStart(object sender, StartupEventArgs e)
{
    Current.ShutdownMode = ShutdownMode.OnExplicitShutdown;

    var dialog = new UserView();

    if (dialog.ShowDialog() == true)
    {
        var mainWindow = new MainWindow();
        Current.ShutdownMode = ShutdownMode.OnMainWindowClose;
        Current.MainWindow = mainWindow;
        mainWindow.Show();
    }
    else
    {
        MessageBox.Show("Unable to load application.", "Error", MessageBoxButton.OK);
        Current.Shutdown(-1);
    }
}

问题:如何Window control从ViewModel 关闭登录名?

提前致谢。


阅读 805

收藏
2020-05-19

共1个答案

小编典典

您可以使用将窗口传递给ViewModel CommandParameter。请参阅下面的示例。

我已经实现了一个CloseWindow方法,该方法将Windows作为参数并将其关闭。窗口通过传递给ViewModel
CommandParameter。请注意,您需要为x:Name应该关闭的窗口定义一个。在我的XAML窗口中,我通过调用此方法,Command并使用将窗口本身作为参数传递给ViewModel
CommandParameter

Command="{Binding CloseWindowCommand, Mode=OneWay}" 
CommandParameter="{Binding ElementName=TestWindow}"

视图模型

public RelayCommand<Window> CloseWindowCommand { get; private set; }

public MainViewModel()
{
    this.CloseWindowCommand = new RelayCommand<Window>(this.CloseWindow);
}

private void CloseWindow(Window window)
{
    if (window != null)
    {
       window.Close();
    }
}

视图

<Window x:Class="ClientLibTestTool.ErrorView"
        x:Name="TestWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:localization="clr-namespace:ClientLibTestTool.ViewLanguages"
        DataContext="{Binding Main, Source={StaticResource Locator}}"
        Title="{x:Static localization:localization.HeaderErrorView}"
        Height="600" Width="800"
        ResizeMode="NoResize"
        WindowStartupLocation="CenterScreen">
    <Grid> 
        <Button Content="{x:Static localization:localization.ButtonClose}" 
                Height="30" 
                Width="100" 
                Margin="0,0,10,10" 
                IsCancel="True" 
                VerticalAlignment="Bottom" 
                HorizontalAlignment="Right" 
                Command="{Binding CloseWindowCommand, Mode=OneWay}" 
                CommandParameter="{Binding ElementName=TestWindow}"/>
    </Grid>
</Window>

请注意,我使用的是MVVM light框架,但是该原理适用于每个wpf应用程序。

该解决方案违反了MVVM模式,因为视图模型对UI实现一无所知。如果要严格遵循MVVM编程范例,则必须使用接口抽象视图的类型。

MVVM一致性解决方案 (以前的EDIT2)

用户 Crono 在评论部分提到了一个有效的观点:

将Window对象传递给视图模型会破坏MVVM模式恕我直言,因为它迫使您的vm知道正在查看的内容。

您可以通过引入包含close方法的接口来解决此问题。

接口:

public interface ICloseable
{
    void Close();
}

重构的ViewModel将如下所示:

视图模型

public RelayCommand<ICloseable> CloseWindowCommand { get; private set; }

public MainViewModel()
{
    this.CloseWindowCommand = new RelayCommand<IClosable>(this.CloseWindow);
}

private void CloseWindow(ICloseable window)
{
    if (window != null)
    {
        window.Close();
    }
}

您必须引用并实现ICloseable视图中的接口

查看(后面的代码)

public partial class MainWindow : Window, ICloseable
{
    public MainWindow()
    {
        InitializeComponent();
    }
}

回答原始问题:( 以前是EDIT1)

您的登录按钮(添加了CommandParameter):

<Button Name="btnLogin" IsDefault="True" Content="Login" Command="{Binding ShowLoginCommand}" CommandParameter="{Binding ElementName=LoginWindow}"/>

您的代码:

 public RelayCommand<Window> CloseWindowCommand { get; private set; } // the <Window> is important for your solution!

 public MainViewModel() 
 {
     //initialize the CloseWindowCommand. Again, mind the <Window>
     //you don't have to do this in your constructor but it is good practice, thought
     this.CloseWindowCommand = new RelayCommand<Window>(this.CloseWindow);
 }

 public bool CheckLogin(Window loginWindow) //Added loginWindow Parameter
 {
    var user = context.Users.Where(i => i.Username == this.Username).SingleOrDefault();

    if (user == null)
    {
        MessageBox.Show("Unable to Login, incorrect credentials.");
        return false;
    }
    else if (this.Username == user.Username || this.Password.ToString() == user.Password)
    {
        MessageBox.Show("Welcome "+ user.Username + ", you have successfully logged in.");
        this.CloseWindow(loginWindow); //Added call to CloseWindow Method
        return true;
    }
    else
    {
        MessageBox.Show("Unable to Login, incorrect credentials.");
        return false;
    }
 }

 //Added CloseWindow Method
 private void CloseWindow(Window window)
 {
     if (window != null)
     {
         window.Close();
     }
 }
2020-05-19