我使用a创建一个登录,window control
以允许用户登录WPF
我正在创建的应用程序.
到目前为止,我已经创建了一种方法,用于检查用户是否已输入正确的凭据,username
并password
在textbox
登录屏幕上输入binding
两个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();
}
Run Code Online (Sandbox Code Playgroud)
我也有一个command
,我bind
到中我的按钮,xaml
像这样;
<Button Name="btnLogin" IsDefault="True" Content="Login" Command="{Binding ShowLoginCommand}" />
Run Code Online (Sandbox Code Playgroud)
当我输入用户名和密码时,它会执行适当的代码,无论是正确还是错误.但是,当用户名和密码都正确时,如何从ViewModel关闭此窗口?
我之前尝试使用过dialog modal
但是它没有完全奏效.此外,在我的app.xaml中,我做了类似下面的操作,首先加载登录页面,然后加载实际的应用程序.
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);
}
}
Run Code Online (Sandbox Code Playgroud)
问题:如何Window control
从ViewModel 关闭登录?
提前致谢.
Joe*_*oel 131
您可以使用窗口将窗口传递给ViewModel CommandParameter
.请参阅下面的示例.
我已经实现了一个CloseWindow
方法,它将Windows作为参数并关闭它.窗口通过传递给ViewModel CommandParameter
.请注意,您需要为x:Name
应该关闭的窗口定义一个.在我的XAML窗口中,我通过调用此方法Command
并将窗口本身作为参数传递给ViewModel使用CommandParameter
.
Command="{Binding CloseWindowCommand, Mode=OneWay}"
CommandParameter="{Binding ElementName=TestWindow}"
Run Code Online (Sandbox Code Playgroud)
视图模型
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();
}
}
Run Code Online (Sandbox Code Playgroud)
视图
<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>
Run Code Online (Sandbox Code Playgroud)
请注意,我使用的是MVVM轻量级框架,但主体适用于每个wpf应用程序.
此解决方案违反了MVVM模式,因为视图模型不应该知道有关UI实现的任何信息.如果要严格遵循MVVM编程范例,则必须使用接口抽象视图的类型.
MVVM一致解决方案(前EDIT2)
用户Crono在评论部分提到了一个有效点:
将Window对象传递给视图模型会破坏MVVM模式IMHO,因为它会强制您的虚拟机知道它正在查看的内容.
您可以通过引入包含close方法的接口来解决此问题.
接口:
public interface ICloseable
{
void Close();
}
Run Code Online (Sandbox Code Playgroud)
您重构的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();
}
}
Run Code Online (Sandbox Code Playgroud)
您必须ICloseable
在视图中引用和实现该接口
查看(代码背后)
public partial class MainWindow : Window, ICloseable
{
public MainWindow()
{
InitializeComponent();
}
}
Run Code Online (Sandbox Code Playgroud)
回答原始问题:(前EDIT1)
您的登录按钮(添加了CommandParameter):
<Button Name="btnLogin" IsDefault="True" Content="Login" Command="{Binding ShowLoginCommand}" CommandParameter="{Binding ElementName=LoginWindow}"/>
Run Code Online (Sandbox Code Playgroud)
你的代码:
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();
}
}
Run Code Online (Sandbox Code Playgroud)
Ste*_*eck 31
保持MVVM,我认为使用Blend SDK中的行为(System.Windows.Interactivity)或Prism的自定义交互请求可以很好地适应这种情况.
如果走行为路线,这里是一般的想法:
public class CloseWindowBehavior : Behavior<Window>
{
public bool CloseTrigger
{
get { return (bool)GetValue(CloseTriggerProperty); }
set { SetValue(CloseTriggerProperty, value); }
}
public static readonly DependencyProperty CloseTriggerProperty =
DependencyProperty.Register("CloseTrigger", typeof(bool), typeof(CloseWindowBehavior), new PropertyMetadata(false, OnCloseTriggerChanged));
private static void OnCloseTriggerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var behavior = d as CloseWindowBehavior;
if (behavior != null)
{
behavior.OnCloseTriggerChanged();
}
}
private void OnCloseTriggerChanged()
{
// when closetrigger is true, close the window
if (this.CloseTrigger)
{
this.AssociatedObject.Close();
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后在您的窗口中,您只需将CloseTrigger绑定到一个布尔值,该值将在您希望窗口关闭时设置.
<Window x:Class="TestApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:local="clr-namespace:TestApp"
Title="MainWindow" Height="350" Width="525">
<i:Interaction.Behaviors>
<local:CloseWindowBehavior CloseTrigger="{Binding CloseTrigger}" />
</i:Interaction.Behaviors>
<Grid>
</Grid>
</Window>
Run Code Online (Sandbox Code Playgroud)
最后,您希望窗口关闭时,您的DataContext/ViewModel将具有一个属性,如下所示:
public class MainWindowViewModel : INotifyPropertyChanged
{
private bool closeTrigger;
/// <summary>
/// Gets or Sets if the main window should be closed
/// </summary>
public bool CloseTrigger
{
get { return this.closeTrigger; }
set
{
this.closeTrigger = value;
RaisePropertyChanged("CloseTrigger");
}
}
public MainWindowViewModel()
{
// just setting for example, close the window
CloseTrigger = true;
}
protected void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
Run Code Online (Sandbox Code Playgroud)
(设置你的Window.DataContext = new MainWindowViewModel())
Chr*_*isO 30
当我需要这样做时,我通常会在视图模型上放置一个事件,然后将它连接到Window.Close()
将视图模型绑定到窗口时
public class LoginViewModel
{
public event EventHandler OnRequestClose;
private void Login()
{
// Login logic here
OnRequestClose(this, new EventArgs());
}
}
Run Code Online (Sandbox Code Playgroud)
并在创建登录窗口时
var vm = new LoginViewModel();
var loginWindow = new LoginWindow
{
DataContext = vm
};
vm.OnRequestClose += (s, e) => loginWindow.Close();
loginWindow.ShowDialog();
Run Code Online (Sandbox Code Playgroud)
小智 18
可能会迟到,但这是我的答案
foreach (Window item in Application.Current.Windows)
{
if (item.DataContext == this) item.Close();
}
Run Code Online (Sandbox Code Playgroud)
DHN*_*DHN 12
这是我在几个项目中使用的东西.它可能看起来像一个黑客,但它工作正常.
public class AttachedProperties : DependencyObject //adds a bindable DialogResult to window
{
public static readonly DependencyProperty DialogResultProperty =
DependencyProperty.RegisterAttached("DialogResult", typeof(bool?), typeof(AttachedProperties),
new PropertyMetaData(default(bool?), OnDialogResultChanged));
public bool? DialogResult
{
get { return (bool?)GetValue(DialogResultProperty); }
set { SetValue(DialogResultProperty, value); }
}
private static void OnDialogResultChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var window = d as Window;
if (window == null)
return;
window.DialogResult = (bool?)e.NewValue;
}
}
Run Code Online (Sandbox Code Playgroud)
现在,您可以绑定DialogResult
到VM并设置其属性值.在Window
将关闭,当值设置.
<!-- Assuming that the VM is bound to the DataContext and the bound VM has a property DialogResult -->
<Window someNs:AttachedProperties.DialogResult={Binding DialogResult} />
Run Code Online (Sandbox Code Playgroud)
这是我们生产环境中运行的摘要
<Window x:Class="AC.Frontend.Controls.DialogControl.Dialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:DialogControl="clr-namespace:AC.Frontend.Controls.DialogControl"
xmlns:hlp="clr-namespace:AC.Frontend.Helper"
MinHeight="150" MinWidth="300" ResizeMode="NoResize" SizeToContent="WidthAndHeight"
WindowStartupLocation="CenterScreen" Title="{Binding Title}"
hlp:AttachedProperties.DialogResult="{Binding DialogResult}" WindowStyle="ToolWindow" ShowInTaskbar="True"
Language="{Binding UiCulture, Source={StaticResource Strings}}">
<!-- A lot more stuff here -->
</Window>
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,我xmlns:hlp="clr-namespace:AC.Frontend.Helper"
首先声明了命名空间,然后是绑定hlp:AttachedProperties.DialogResult="{Binding DialogResult}"
.
在AttachedProperty
这个样子的.这与我昨天发布的不一样,但恕我直言它应该没有任何影响.
public class AttachedProperties
{
#region DialogResult
public static readonly DependencyProperty DialogResultProperty =
DependencyProperty.RegisterAttached("DialogResult", typeof (bool?), typeof (AttachedProperties), new PropertyMetadata(default(bool?), OnDialogResultChanged));
private static void OnDialogResultChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var wnd = d as Window;
if (wnd == null)
return;
wnd.DialogResult = (bool?) e.NewValue;
}
public static bool? GetDialogResult(DependencyObject dp)
{
if (dp == null) throw new ArgumentNullException("dp");
return (bool?)dp.GetValue(DialogResultProperty);
}
public static void SetDialogResult(DependencyObject dp, object value)
{
if (dp == null) throw new ArgumentNullException("dp");
dp.SetValue(DialogResultProperty, value);
}
#endregion
}
Run Code Online (Sandbox Code Playgroud)
Ras*_*ssK 12
简单的方法
public interface IRequireViewIdentification
{
Guid ViewID { get; }
}
Run Code Online (Sandbox Code Playgroud)
实现ViewModel
public class MyViewVM : IRequireViewIdentification
{
private Guid _viewId;
public Guid ViewID
{
get { return _viewId; }
}
public MyViewVM()
{
_viewId = Guid.NewGuid();
}
}
Run Code Online (Sandbox Code Playgroud)
添加常规窗口管理器帮助程序
public static class WindowManager
{
public static void CloseWindow(Guid id)
{
foreach (Window window in Application.Current.Windows)
{
var w_id = window.DataContext as IRequireViewIdentification;
if (w_id != null && w_id.ViewID.Equals(id))
{
window.Close();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
并在viewmodel中关闭它
WindowManager.CloseWindow(ViewID);
Run Code Online (Sandbox Code Playgroud)
这个怎么样?
视图模型:
class ViewModel
{
public Action CloseAction { get; set; }
private void Stuff()
{
// Do Stuff
CloseAction(); // closes the window
}
}
Run Code Online (Sandbox Code Playgroud)
在您的 ViewModel 中,使用 CloseAction() 关闭窗口,就像上面的示例一样。
看法:
public View()
{
InitializeComponent();
ViewModel vm = new ViewModel (); // this creates an instance of the ViewModel
this.DataContext = vm; // this sets the newly created ViewModel as the DataContext for the View
if (vm.CloseAction == null)
vm.CloseAction = new Action(() => this.Close());
}
Run Code Online (Sandbox Code Playgroud)
我知道这是一篇旧帖子,可能没有人会滚动这么远,我知道我没有。所以,经过几个小时的尝试不同的东西,我找到了这个博客,伙计把它杀了。最简单的方法来做到这一点,试过了,它就像一个魅力。
在视图模型中:
...
public bool CanClose { get; set; }
private RelayCommand closeCommand;
public ICommand CloseCommand
{
get
{
if(closeCommand == null)
(
closeCommand = new RelayCommand(param => Close(), param => CanClose);
)
}
}
public void Close()
{
this.Close();
}
...
Run Code Online (Sandbox Code Playgroud)
向 ViewModel 添加 Action 属性,但从 View 的代码隐藏文件中定义它。这将让我们在 ViewModel 上动态定义一个指向 View 的引用。
在 ViewModel 上,我们只需添加:
public Action CloseAction { get; set; }
Run Code Online (Sandbox Code Playgroud)
在视图上,我们将其定义为:
public View()
{
InitializeComponent() // this draws the View
ViewModel vm = new ViewModel(); // this creates an instance of the ViewModel
this.DataContext = vm; // this sets the newly created ViewModel as the DataContext for the View
if ( vm.CloseAction == null )
vm.CloseAction = new Action(() => this.Close());
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
96544 次 |
最近记录: |