我使用创建了一个Login,window control以允许用户登录到WPF我正在创建的应用程序。
window control
WPF
到目前为止,我已经创建了一个检查用户是否已经在为正确的凭据进入了一个方法username,并password在textbox登录屏幕,上binding2 properties。
username
password
textbox
binding
properties
我是通过创建一个bool像这样的方法来实现的;
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(); }
我也有一个command我bind对我的按钮之类的xaml东西;
command
bind
xaml
<Button Name="btnLogin" IsDefault="True" Content="Login" Command="{Binding ShowLoginCommand}" />
当我输入用户名和密码时,它会执行适当的代码,无论是对还是错。但是,当用户名和密码均正确时,如何从ViewModel中关闭此窗口?
我以前尝试过使用a,dialog modal但效果不佳。此外,在我的app.xaml中,我做了如下操作,首先加载登录页面,然后为true,则加载实际的应用程序。
dialog modal
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 关闭登录名?
Window control
提前致谢。
您可以使用将窗口传递给ViewModel CommandParameter。请参阅下面的示例。
CommandParameter
我已经实现了一个CloseWindow方法,该方法将Windows作为参数并将其关闭。窗口通过传递给ViewModel CommandParameter。请注意,您需要为x:Name应该关闭的窗口定义一个。在我的XAML窗口中,我通过调用此方法,Command并使用将窗口本身作为参数传递给ViewModel CommandParameter。
CloseWindow
x:Name
Command
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视图中的接口
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(); } }