我正在尝试学习WPF和MVVM问题,但是遇到了麻烦。 这个问题类似但不完全相同as this one (handling-dialogs-in-wpf-with-mvvm) ......
我有一个使用MVVM模式编写的“登录”表单。
此表单包含一个ViewModel,其中包含用户名和密码,这些用户名和密码使用普通数据绑定绑定到XAML中的视图。 它还有一个“登录”命令,该命令绑定到表单上的“登录”按钮,使用常规数据绑定。
当“Login”命令触发时,它会调用ViewModel中的一个函数,该函数将关闭并通过网络发送数据以进行登录。当此函数完成时,有2个操作:
登录无效 - 我们只显示一个MessageBox,一切正常
登录有效,我们需要关闭“登录”表单并将其返回为DialogResult
...
问题是,ViewModel对实际视图一无所知,那么如何关闭视图并告诉它返回特定的DialogResult?我可以在CodeBehind中粘贴一些代码,和/或将View传递给ViewModel,但这似乎会完全击败MVVM的整个点......
最后,我刚刚违反了MVVM模式的“纯度”,并让View发布了Closed
事件,并公开了Close
方法。然后,ViewModel将调用view.Close
。该视图仅通过接口已知并通过IOC容器连接,因此不会丢失可测试性或可维护性。
接受的答案是-5票,这似乎很愚蠢!虽然我很清楚通过在“纯粹”时解决问题所获得的良好感受,当然我不是唯一一个认为200行事件,命令和行为只是为了避免单线方法的人“模式”和“纯度”的名称有点荒谬......
答案 0 :(得分:311)
答案 1 :(得分:64)
从我的角度来看,问题非常好,因为同样的方法不仅用于“登录”窗口,而且用于任何类型的窗口。我已经回顾了很多建议,没有一个对我来说没问题。请查看我从MVVM design pattern article。
中提取的建议每个ViewModel类都应继承WorkspaceViewModel
具有RequestClose
类型的CloseCommand
事件和ICommand
属性的CloseCommand
。 RequestClose
属性的默认实现将引发OnLoaded
事件。
为了关闭窗口,应该覆盖窗口的void CustomerWindow_Loaded(object sender, RoutedEventArgs e)
{
CustomerViewModel customer = CustomerViewModel.GetYourCustomer();
DataContext = customer;
customer.RequestClose += () => { Close(); };
}
方法:
OnStartup
您应用的或 protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
MainWindow window = new MainWindow();
var viewModel = new MainWindowViewModel();
viewModel.RequestClose += window.Close;
window.DataContext = viewModel;
window.Show();
}
方法:
RequestClose
我想CloseCommand
中的WorkspaceViewModel
事件和public abstract class WorkspaceViewModel : ViewModelBase
// There's nothing interesting in ViewModelBase as it only implements the INotifyPropertyChanged interface
{
RelayCommand _closeCommand;
public ICommand CloseCommand
{
get
{
if (_closeCommand == null)
{
_closeCommand = new RelayCommand(
param => Close(),
param => CanClose()
);
}
return _closeCommand;
}
}
public event Action RequestClose;
public virtual void Close()
{
if ( RequestClose != null )
{
RequestClose();
}
}
public virtual bool CanClose()
{
return true;
}
}
属性实现非常清楚,但我会证明它们是一致的:
RelayCommand
public class RelayCommand : ICommand
{
#region Constructors
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion // Constructors
#region ICommand Members
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
#endregion // ICommand Members
#region Fields
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
#endregion // Fields
}
的源代码:
{{1}}
P.S。不要因为这些来源对我不好!如果我昨天有他们,那将节省我几个小时......
P.P.S。欢迎任何意见或建议。
答案 2 :(得分:18)
我使用附加行为来关闭窗口。 将ViewModel上的“signal”属性绑定到附加行为(我实际上使用了一个触发器) 当它设置为true时,该行为将关闭窗口。
http://adammills.wordpress.com/2009/07/01/window-close-from-xaml/
答案 3 :(得分:15)
有很多评论在这里争论MVVM的优点和缺点。对我来说,我同意Nir;这是一个适当使用模式的问题,MVVM并不总是适合。人们似乎已经愿意牺牲所有最重要的软件设计原则,以使其适合MVVM。
那就是说..我认为你的情况可能适合一点点重构。
在大多数情况下,我遇到过,WPF使您无需多个Window
。也许您可以尝试使用Frame
和Page
代替Windows DialogResult
s。
在您的情况下,我的建议是LoginFormViewModel
处理LoginCommand
,如果登录无效,请将LoginFormViewModel
上的属性设置为适当的值(false
或一些枚举值,如UserAuthenticationStates.FailedAuthentication
)。为成功登录(true
或其他枚举值),您也会这样做。然后,您可以使用DataTrigger
响应各种用户身份验证状态,并使用简单的Setter
来更改Source
的{{1}}属性。
让您的登录窗口返回Frame
我认为是您感到困惑的地方; DialogResult
实际上是ViewModel的属性。在我看来,WPF的经验有限,当一些事情感觉不对时,通常是因为我在考虑如何在WinForms中做同样的事情。
希望有所帮助。
答案 4 :(得分:9)
假设您的登录对话框是第一个创建的窗口,请在LoginViewModel类中尝试:
void OnLoginResponse(bool loginSucceded)
{
if (loginSucceded)
{
Window1 window = new Window1() { DataContext = new MainWindowViewModel() };
window.Show();
App.Current.MainWindow.Close();
App.Current.MainWindow = window;
}
else
{
LoginError = true;
}
}
答案 5 :(得分:6)
我处理它的方法是在我的ViewModel中添加一个事件处理程序。当用户成功登录后,我将触发该事件。在我的视图中,我会附加到此事件,当它被解雇时,我会关闭窗口。
答案 6 :(得分:5)
这是一个简单而干净的解决方案 - 您可以向ViewModel添加一个事件,并指示Window在触发该事件时自行关闭。
有关详细信息,请参阅我的博客帖子Close window from ViewModel。
答案 7 :(得分:4)
这是我最初做的,哪些确实有效,但它似乎相当啰嗦和丑陋(全局静态任何东西永远都不好)
1:App.xaml.cs
public partial class App : Application
{
// create a new global custom WPF Command
public static readonly RoutedUICommand LoggedIn = new RoutedUICommand();
}
2:LoginForm.xaml
// bind the global command to a local eventhandler
<CommandBinding Command="client:App.LoggedIn" Executed="OnLoggedIn" />
3:LoginForm.xaml.cs
// implement the local eventhandler in codebehind
private void OnLoggedIn( object sender, ExecutedRoutedEventArgs e )
{
DialogResult = true;
Close();
}
4:LoginFormViewModel.cs
// fire the global command from the viewmodel
private void OnRemoteServerReturnedSuccess()
{
App.LoggedIn.Execute(this, null);
}
我后来删除了所有这些代码,只是让LoginFormViewModel
在它的视图上调用了Close方法。它最终变得更好,更容易遵循。恕我直言,模式的重点是让人们更容易理解你的应用正在做什么,在这种情况下,MVVM让它更难理解,比如果我没有使用它,现在是反 -pattern。
答案 8 :(得分:3)
仅供参考,我遇到了同样的问题,我想我想出了一个不需要全局或静态的解决方案,尽管它可能不是最好的答案。我让你们自己决定。
在我的例子中,实例化要显示的Window的ViewModel(让我们称之为ViewModelMain)也知道LoginFormViewModel(以上面的情况为例)。
所以我做的是在LoginFormViewModel上创建一个类型为ICommand的属性(让我们称之为CloseWindowCommand)。然后,在我在Window上调用.ShowDialog()之前,我将LoginFormViewModel上的CloseWindowCommand属性设置为我实例化的Window.Close()方法。然后在LoginFormViewModel里面我只需要调用CloseWindowCommand.Execute()来关闭窗口。
我认为这是一种解决方法/黑客攻击,但它在没有真正打破MVVM模式的情况下运行良好。
随意批评这个过程,我可以接受它! :)
答案 9 :(得分:3)
这可能已经很晚了,但我遇到了同样的问题,我发现了一个适合我的解决方案。
我无法弄清楚如何在没有对话框的情况下创建应用程序(可能只是一个心灵障碍)。所以我与MVVM陷入僵局并展示了一个对话框。所以我遇到了这篇CodeProject文章:
http://www.codeproject.com/KB/WPF/XAMLDialog.aspx
这是一个UserControl,它基本上允许窗口在另一个窗口的可视树中(xaml中不允许)。它还公开了一个名为IsShowing的布尔值DependencyPropert。
你可以设置一个样式,通常在resourcedictionary中,当控件的Content属性通过触发器时,基本上显示对话框!= null:
<Style TargetType="{x:Type d:Dialog}">
<Style.Triggers>
<Trigger Property="HasContent" Value="True">
<Setter Property="Showing" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
在要显示对话框的视图中,只需输入:
<d:Dialog Content="{Binding Path=DialogViewModel}"/>
在你的ViewModel中你所要做的就是将属性设置为一个值(注意:ViewModel类必须支持INotifyPropertyChanged才能让视图知道发生的事情。)
像这样:DialogViewModel = new DisplayViewModel();
要将ViewModel与View匹配,您应该在resourcedictionary中使用这样的内容:
<DataTemplate DataType="{x:Type vm:DisplayViewModel}">
<vw:DisplayView/>
</DataTemplate>
通过所有这些,您可以获得一个单行代码来显示对话框。你得到的问题是你不能只用上面的代码关闭对话框。这就是为什么你必须在一个ViewModel基类中放入一个事件,DisplayViewModel继承自上面的代码,而不是上面的代码,写这个
var vm = new DisplayViewModel();
vm.RequestClose += new RequestCloseHandler(DisplayViewModel_RequestClose);
DialogViewModel = vm;
然后您可以通过回调来处理对话框的结果。
这可能看起来有点复杂,但一旦奠定了基础,它就非常简单。这又是我的实现,我相信还有其他的:)
希望这有帮助,它救了我。
答案 10 :(得分:3)
public partial class MyWindow: Window
{
public ApplicationSelection()
{
InitializeComponent();
MyViewModel viewModel = new MyViewModel();
DataContext = viewModel;
viewModel.RequestClose += () => { Close(); };
}
}
public class MyViewModel
{
//...Your code...
public event Action RequestClose;
public virtual void Close()
{
if (RequestClose != null)
{
RequestClose();
}
}
public void SomeFunction()
{
//...Do something...
Close();
}
}
答案 11 :(得分:3)
好的,所以这个问题将近6岁,我仍然无法在这里找到我认为这是正确的答案,所以请允许我分享我的“2美分”......
我实际上有两种方法可以做到,第一种方法是简单的方式......第二种是右方方式,所以如果你正在寻找合适的方式,只需跳过#1并跳转到#2 强>:
如果我只有一个小项目,我有时只在ViewModel中创建一个 CloseWindowAction :
public Action CloseWindow { get; set; } // In MyViewModel.cs
无论谁创建了View,或者在View后面的代码中,我只需设置Action将调用的方法:
(记住MVVM是关于View和ViewModel的分离...... View的代码behins仍然是View,只要有正确的分离,你就不会违反模式)
如果某些ViewModel创建了一个新窗口:
private void CreateNewView()
{
MyView window = new MyView();
window.DataContext = new MyViewModel
{
CloseWindow = window.Close,
};
window.ShowDialog();
}
或者如果你想在主窗口中使用它,只需将它放在View的构造函数下:
public MyView()
{
InitializeComponent();
this.DataContext = new MainViewModel
{
CloseWindow = this.Close
};
}
如果要关闭窗口,只需在ViewModel上调用Action。
现在正确的做法是使用 Prism (恕我直言),所有相关内容都可以found here。
您可以制作交互请求,使用新窗口中需要的任何数据填充它,午餐,关闭它甚至接收数据。所有这些封装和MVVM批准。您甚至获取窗口关闭状态的状态,例如用户Canceled
或Accepted
(确定按钮)窗口,如果您需要,则返回数据即可。它有点复杂,答案#1,但它更完整,是微软推荐的模式。
我给出的链接包含所有代码片段和示例,所以我不打算在这里放置任何代码,只需阅读Prism Quick Start的下载文章并运行它,只需要一点点就可以了解它更加冗长以使其发挥作用,但其好处远远大于关闭窗口。
答案 12 :(得分:2)
您可以让ViewModel公开View注册的事件。然后,当ViewModel决定关闭视图的时间时,它会触发导致视图关闭的事件。如果您希望传回特定的结果值,那么您将在ViewModel中拥有一个属性。
答案 13 :(得分:0)
行为是这里最方便的方式。
一方面,它可以绑定到给定的viewmodel(可以 信号“关闭表格!”)
另一方面,它可以访问表单本身,因此可以订阅必要的表单特定事件,或显示确认对话框或其他任何内容。
第一次看到写作必要的行为很无聊。但是,从现在开始,您可以通过精确的单线程XAML片段在所需的每个表单上重复使用它。如有必要,您可以将其作为单独的程序集提取,以便它可以包含在您想要的任何下一个项目中。
答案 14 :(得分:0)
在 Dependency Property
/任意View
(或您要关闭的UserControl
)中创建 Window
。如下所示:
public bool CloseTrigger
{
get { return (bool)GetValue(CloseTriggerProperty); }
set { SetValue(CloseTriggerProperty, value); }
}
public static readonly DependencyProperty CloseTriggerProperty =
DependencyProperty.Register("CloseTrigger", typeof(bool), typeof(ControlEventBase), new PropertyMetadata(new PropertyChangedCallback(OnCloseTriggerChanged)));
private static void OnCloseTriggerChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
{
//write Window Exit Code
}
并从 ViewModel的属性中绑定:
<Window x:Class="WpfStackOverflowTempProject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Width="525"
CloseTrigger="{Binding Path=CloseWindow,Mode=TwoWay}"
属性 VeiwModel
:
private bool closeWindow;
public bool CloseWindow
{
get { return closeWindow; }
set
{
closeWindow = value;
RaiseChane("CloseWindow");
}
}
现在,通过更改ViewModel中的 CloseWindow
值来触发关闭操作。 :)
答案 15 :(得分:0)
这是一个简单的无错解决方案(带源代码),它对我有用。
从INotifyPropertyChanged
在ViewModel中创建一个可观察的属性 CloseDialog
public void Execute()
{
// Do your task here
// if task successful, assign true to CloseDialog
CloseDialog = true;
}
private bool _closeDialog;
public bool CloseDialog
{
get { return _closeDialog; }
set { _closeDialog = value; OnPropertyChanged(); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName]string property = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
在视图中附加处理程序以进行此属性更改
_loginDialogViewModel = new LoginDialogViewModel();
loginPanel.DataContext = _loginDialogViewModel;
_loginDialogViewModel.PropertyChanged += OnPropertyChanged;
现在你差不多完成了。在事件处理程序中生成DialogResult = true
protected void OnPropertyChanged(object sender, PropertyChangedEventArgs args)
{
if (args.PropertyName == "CloseDialog")
{
DialogResult = true;
}
}
答案 16 :(得分:0)
虽然这没有回答如何通过viewmodel执行此操作的问题,但这确实显示了如何仅使用XAML +混合SDK来执行此操作。
我选择下载并使用Blend SDK中的两个文件,您可以通过NuGet将这两个文件作为Microsoft的软件包。文件是:
System.Windows.Interactivity.dll和Microsoft.Expression.Interactions.dll
Microsoft.Expression.Interactions.dll为您提供了很好的功能,例如能够在您的viewmodel或其他目标上设置属性或调用方法,并且还有其他小部件。
一些XAML:
<Window x:Class="Blah.Blah.MyWindow"
...
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
...>
<StackPanel>
<Button x:Name="OKButton" Content="OK">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ei:ChangePropertyAction
TargetObject="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"
PropertyName="DialogResult"
Value="True"
IsEnabled="{Binding SomeBoolOnTheVM}" />
</i:EventTrigger>
</Button>
<Button x:Name="CancelButton" Content="Cancel">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ei:ChangePropertyAction
TargetObject="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"
PropertyName="DialogResult"
Value="False" />
</i:EventTrigger>
</Button>
<Button x:Name="CloseButton" Content="Close">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<!-- method being invoked should be void w/ no args -->
<ei:CallMethodAction
TargetObject="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"
MethodName="Close" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<StackPanel>
</Window>
请注意,如果您只是简单的确定/取消行为,只要窗口显示为Window.ShowDialog(),您就可以使用IsDefault和IsCancel属性。 我个人遇到问题,有一个IsDefault属性设置为true的按钮,但是在加载页面时它被隐藏了。它显示后似乎不想很好地播放,所以我只是设置了如上所示的Window.DialogResult属性,它适用于我。
答案 17 :(得分:0)
我已经阅读了所有的答案,但我必须说,其中大多数都不够好甚至更糟。
您可以使用 DialogService 类来处理此问题,该类负责显示对话框窗口并返回对话框结果。我创建了sample project来证明它的实现和使用。
这里是最重要的部分:
//we will call this interface in our viewmodels
public interface IDialogService
{
bool? ShowDialog(object dialogViewModel, string caption);
}
//we need to display logindialog from mainwindow
public class MainWindowViewModel : ViewModelBase
{
public string Message {get; set;}
public void ShowLoginCommandExecute()
{
var loginViewModel = new LoginViewModel();
var dialogResult = this.DialogService.ShowDialog(loginViewModel, "Please, log in");
//after dialog is closed, do someting
if (dialogResult == true && loginViewModel.IsLoginSuccessful)
{
this.Message = string.Format("Hello, {0}!", loginViewModel.Username);
}
}
}
public class DialogService : IDialogService
{
public bool? ShowDialog(object dialogViewModel, string caption)
{
var contentView = ViewLocator.GetView(dialogViewModel);
var dlg = new DialogWindow
{
Title = caption
};
dlg.PART_ContentControl.Content = contentView;
return dlg.ShowDialog();
}
}
这不是更简单吗?比EventAggregator或其他类似解决方案更简洁,更易读,最后但更不容易调试?
正如您所看到的,在我的视图模型中,我已经使用了我在帖子中描述的ViewModel第一种方法:Best practice for calling View from ViewModel in WPF
当然,在现实世界中,DialogService.ShowDialog
必须有更多选项来配置对话框,例如他们应该执行的按钮和命令。有不同的方式这样做,但它超出了范围:)
答案 18 :(得分:0)
我会这样:
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
// View
public partial class TestCloseWindow : Window
{
public TestCloseWindow() {
InitializeComponent();
Messenger.Default.Register<CloseWindowMsg>(this, (msg) => Close());
}
}
// View Model
public class MainViewModel: ViewModelBase
{
ICommand _closeChildWindowCommand;
public ICommand CloseChildWindowCommand {
get {
return _closeChildWindowCommand?? (_closeChildWindowCommand = new RelayCommand(() => {
Messenger.Default.Send(new CloseWindowMsg());
}));
}
}
}
public class CloseWindowMsg
{
}
答案 19 :(得分:0)
我最终混合了Joe White's answer和Adam Mills's answer中的一些代码,因为我需要在编程创建的窗口中显示用户控件。所以DialogCloser不需要在窗口上,它可以在用户控件本身上
<UserControl ...
xmlns:xw="clr-namespace:Wpf"
xw:DialogCloser.DialogResult="{Binding DialogResult}">
如果用户控件没有附加到窗口本身,DialogCloser会找到它的窗口。
namespace Wpf
{
public static class DialogCloser
{
public static readonly DependencyProperty DialogResultProperty =
DependencyProperty.RegisterAttached(
"DialogResult",
typeof(bool?),
typeof(DialogCloser),
new PropertyMetadata(DialogResultChanged));
private static void DialogResultChanged(
DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var window = d.GetWindow();
if (window != null)
window.DialogResult = e.NewValue as bool?;
}
public static void SetDialogResult(DependencyObject target, bool? value)
{
target.SetValue(DialogResultProperty, value);
}
}
public static class Extensions
{
public static Window GetWindow(this DependencyObject sender_)
{
Window window = sender_ as Window;
return window ?? Window.GetWindow( sender_ );
}
}
}
答案 20 :(得分:0)
我实施了Joe White的解决方案,但偶尔遇到问题&#34; 只有在创建Window并显示为对话框&#34;后才能设置DialogResult。错误。
我在View关闭后保持ViewModel,偶尔我后来使用相同的VM打开了一个新的View。看来在旧View被垃圾收集之前关闭新视图会导致 DialogResultChanged 尝试在关闭的窗口上设置 DialogResult 属性,从而引发错误。
我的解决方法是更改 DialogResultChanged 以检查窗口的 IsLoaded 属性:
private static void DialogResultChanged(
DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var window = d as Window;
if (window != null && window.IsLoaded)
window.DialogResult = e.NewValue as bool?;
}
进行此更改后,将忽略对已关闭对话框的任何附件。
答案 21 :(得分:0)
另一个解决方案是在View Model中使用INotifyPropertyChanged创建属性,如DialogResult,然后在Code Behind中写下这个:
public class SomeWindow: ChildWindow
{
private SomeViewModel _someViewModel;
public SomeWindow()
{
InitializeComponent();
this.Loaded += SomeWindow_Loaded;
this.Closed += SomeWindow_Closed;
}
void SomeWindow_Loaded(object sender, RoutedEventArgs e)
{
_someViewModel = this.DataContext as SomeViewModel;
_someViewModel.PropertyChanged += _someViewModel_PropertyChanged;
}
void SomeWindow_Closed(object sender, System.EventArgs e)
{
_someViewModel.PropertyChanged -= _someViewModel_PropertyChanged;
this.Loaded -= SomeWindow_Loaded;
this.Closed -= SomeWindow_Closed;
}
void _someViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == SomeViewModel.DialogResultPropertyName)
{
this.DialogResult = _someViewModel.DialogResult;
}
}
}
最重要的片段是_someViewModel_PropertyChanged
。
DialogResultPropertyName
可以是SomeViewModel
中的一些公共const字符串。
如果在ViewModel中很难做到这一点,我会使用这种技巧在View Controls中进行一些更改。在ViewModel中的OnPropertyChanged,您可以在View中执行任何操作。 ViewModel仍然是“单元可测试的”,代码中的一些小代码行没有区别。
答案 22 :(得分:0)
为了增加大量的答案,我想添加以下内容。假设您的ViewModel上有一个ICommand,并且您希望该命令关闭其窗口(或任何其他操作),您可以使用以下内容。
var windows = Application.Current.Windows;
for (var i=0;i< windows.Count;i++ )
if (windows[i].DataContext == this)
windows[i].Close();
它并不完美,可能很难测试(因为很难模拟/存根静态)但它比其他解决方案更清晰(恕我直言)。
埃里克
答案 23 :(得分:0)
为什么不将窗口作为命令参数传递?
C#:
private void Cancel( Window window )
{
window.Close();
}
private ICommand _cancelCommand;
public ICommand CancelCommand
{
get
{
return _cancelCommand ?? ( _cancelCommand = new Command.RelayCommand<Window>(
( window ) => Cancel( window ),
( window ) => ( true ) ) );
}
}
XAML:
<Window x:Class="WPFRunApp.MainWindow"
x:Name="_runWindow"
...
<Button Content="Cancel"
Command="{Binding Path=CancelCommand}"
CommandParameter="{Binding ElementName=_runWindow}" />
答案 24 :(得分:-1)
您需要关闭窗口,只需将其放在viewmodel中:
当当
foreach (Window window in Application.Current.Windows)
{
if (window.DataContext == this)
{
window.Close();
return;
}
}
答案 25 :(得分:-10)
Application.Current.MainWindow.Close()
太多了!