WPF MVVM: 如何关闭窗口

我有一个 Button,当我点击它时,它会关闭我的窗口:

<Button x:Name="buttonOk"  IsCancel="True">Ok</Button>

没问题,直到我在 Button上加一个 Command

<Button x:Name="buttonOk"
Command="{Binding SaveCommand}"
IsCancel="True">Ok</Button>

现在它不关闭,大概是因为我正在处理 Command。我可以通过放入一个 EventHandler并调用 this.Close()来解决这个问题。

<Button x:Name="buttonOk"
Click="closeWindow"
Command="{Binding SaveCommand}"
IsCancel="True">Ok</Button>

但是现在我的代码中有代码,也就是方法 SaveCommand。我使用的 MVVM 模式和 SaveCommand是唯一的代码在我的代码后面。

我如何以不同的方式做到这一点,以避免在后面使用代码?

157810 次浏览

对于小型应用程序,我使用自己的应用程序控制器来显示、关闭和处理窗口和 DataContext。它是应用程序用户界面的中心点。

是这样的:

//It is singleton, I will just post 2 methods and their invocations
public void ShowNewWindow(Window window, object dataContext = null, bool dialog = true)
{
window.DataContext = dataContext;
addToWindowRegistry(dataContext, window);


if (dialog)
window.ShowDialog();
else
window.Show();


}


public void CloseWindow(object dataContextSender)
{
var correspondingWindows = windowRegistry.Where(c => c.DataContext.Equals(dataContextSender)).ToList();
foreach (var pair in correspondingWindows)
{
pair.Window.Close();
}
}

以及他们对 视图模型的调用:

// Show new Window with DataContext
ApplicationController.Instance.ShowNewWindow(
new ClientCardsWindow(),
new ClientCardsVM(),
false);


// Close Current Window from viewModel
ApplicationController.Instance.CloseWindow(this);

当然,您可以在我的解决方案中找到一些限制。再说一遍: 我用它来做小项目,这就足够了。如果你感兴趣,我可以在这里或其他地方张贴完整的代码/

正如有人评论的那样,我发布的代码对 MVVM 并不友好,那么第二种解决方案呢?

第一,不是 MVVM 解决方案(我不会删除这个作为参考)

XAML:

<Button Name="okButton" Command="{Binding OkCommand}" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}">OK</Button>

视图模型:

public ICommand OkCommand
{
get
{
if (_okCommand == null)
{
_okCommand = new ActionCommand<Window>(DoOk, CanDoOk);
}
return _okCommand ;
}
}


void DoOk(Window win)
{
// Your Code
win.DialogResult = true;
win.Close();
}


bool CanDoOk(Window win) { return true; }

第二,可能是更好的解决方案: 使用附加行为

XAML

<Button Content="Ok and Close" Command="{Binding OkCommand}" b:CloseOnClickBehaviour.IsEnabled="True" />

视图模型

public ICommand OkCommand
{
get { return _okCommand; }
}

行为课 类似的东西:

public static class CloseOnClickBehaviour
{
public static readonly DependencyProperty IsEnabledProperty =
DependencyProperty.RegisterAttached(
"IsEnabled",
typeof(bool),
typeof(CloseOnClickBehaviour),
new PropertyMetadata(false, OnIsEnabledPropertyChanged)
);


public static bool GetIsEnabled(DependencyObject obj)
{
var val = obj.GetValue(IsEnabledProperty);
return (bool)val;
}


public static void SetIsEnabled(DependencyObject obj, bool value)
{
obj.SetValue(IsEnabledProperty, value);
}


static void OnIsEnabledPropertyChanged(DependencyObject dpo, DependencyPropertyChangedEventArgs args)
{
var button = dpo as Button;
if (button == null)
return;


var oldValue = (bool)args.OldValue;
var newValue = (bool)args.NewValue;


if (!oldValue && newValue)
{
button.Click += OnClick;
}
else if (oldValue && !newValue)
{
button.PreviewMouseLeftButtonDown -= OnClick;
}
}


static void OnClick(object sender, RoutedEventArgs e)
{
var button = sender as Button;
if (button == null)
return;


var win = Window.GetWindow(button);
if (win == null)
return;


win.Close();
}


}

我个人会用一种行为来做这种事:

public class WindowCloseBehaviour : Behavior<Window>
{
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register(
"Command",
typeof(ICommand),
typeof(WindowCloseBehaviour));


public static readonly DependencyProperty CommandParameterProperty =
DependencyProperty.Register(
"CommandParameter",
typeof(object),
typeof(WindowCloseBehaviour));


public static readonly DependencyProperty CloseButtonProperty =
DependencyProperty.Register(
"CloseButton",
typeof(Button),
typeof(WindowCloseBehaviour),
new FrameworkPropertyMetadata(null, OnButtonChanged));


public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}


public object CommandParameter
{
get { return GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}


public Button CloseButton
{
get { return (Button)GetValue(CloseButtonProperty); }
set { SetValue(CloseButtonProperty, value); }
}


private static void OnButtonChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var window = (Window)((WindowCloseBehaviour)d).AssociatedObject;
((Button) e.NewValue).Click +=
(s, e1) =>
{
var command = ((WindowCloseBehaviour)d).Command;
var commandParameter = ((WindowCloseBehaviour)d).CommandParameter;
if (command != null)
{
command.Execute(commandParameter);
}
window.Close();
};
}
}

然后你可以把这个连接到你的 WindowButton来完成这项工作:

<Window x:Class="WpfApplication6.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:local="clr-namespace:WpfApplication6"
Title="Window1" Height="300" Width="300">
<i:Interaction.Behaviors>
<local:WindowCloseBehaviour CloseButton="{Binding ElementName=closeButton}"/>
</i:Interaction.Behaviors>
<Grid>
<Button Name="closeButton">Close</Button>
</Grid>
</Window>

我在这里添加了 CommandCommandParameter,这样您就可以在 Window关闭之前运行一个命令。

这个任务有一个有用的行为,它不会破坏 MVVM,这是一个行为,由 Expression Blend 3引入,允许 View 连接到完全在 ViewModel 中定义的命令。

此行为演示了一种简单的技术,允许 控件中的视图的结束事件 模型-视图-视图模型应用程序。

这允许您在视图(UserControl)中挂接一个行为,该行为 将提供对控件的 Window 的控制,允许 ViewModel 控制窗口是否可以通过标准的 ICommand 关闭。

使用行为允许 ViewModel 管理 M-V-VM 中的视图生命周期

Http://gallery.expression.microsoft.com/windowclosebehavior/

上面的链接已经存档到 http://code.msdn.microsoft.com/Window-Close-Attached-fef26a66#content

我试图用一些通用的 MVVM 方法来解决这个问题,但是我总是发现我最终得到的是不必要的复杂逻辑。为了实现亲密行为,我破例使用了无代码隐藏的规则,并在代码隐藏中使用了很好的 ol’事件:

XAML:

<Button Content="Close" Click="OnCloseClicked" />

暗号:

private void OnCloseClicked(object sender, EventArgs e)
{
Visibility = Visibility.Collapsed;
}

虽然我希望使用命令/MVVM 能够更好地支持这一点,但我只是认为没有比使用事件更简单、更清晰的解决方案了。

我一直在寻找解决同样问题的方法,发现按照下面的方法可以很好地工作。解决办法类似于 OP 在其问题中提到的,但有一些不同之处:

  1. 不需要 IsCancel属性。

  2. 后面的代码不应该关闭窗口。只需设置 DialogResult

在我的例子中,它首先执行后面的代码,然后查看绑定到按钮的模型命令。

XAML

<Button x:Name="buttonOk" Click="Save_Click" Command="{Binding SaveCommand}">OK</Button>

暗号

private void Apply_OnClick(object sender, RoutedEventArgs e)
{
this.DialogResult = true;
}

视图模型

private void Save()
{
// Save data.
}

希望这个能帮上忙。

我刚刚完成了关于这个主题的 博客文章课程。简而言之,使用 getset访问器向 ViewModel 添加一个 Action属性。然后从 View构造函数定义 Action。最后,在绑定命令中调用应该关闭窗口的操作。

视图模型:

public Action CloseAction  { get; set;}

View构造函数中:

private View()
{
InitializeComponent();
ViewModel vm = new ViewModel();
this.DataContext = vm;
if ( vm.CloseAction == null )
vm.CloseAction = new Action(this.Close);
}

最后,在应该关闭窗口的绑定命令中,我们可以简单地调用

CloseAction(); // Calls Close() method of the View

这对我来说很有用,看起来是一个相当优雅的解决方案,并且为我节省了大量的编码工作。

你可以重新措辞这个问题,并通过这样做-拿出另一个解决方案。 如何在 MVVM 环境中启用视图、视图模型和其他东西之间的通信? 你可以使用调解人模式。基本上就是个通知系统。对于实际的中介实现,谷歌为它或问我,我可以电子邮件它。

创建用于关闭视图的 Command。

public void Execute( object parameter )
{
this.viewModel.DisposeMyStuff();
Mediator.NotifyColleagues(Mediator.Token.ConfigWindowShouldClose);
}

调解员将发出通知(令牌)

在 View code behind 构造函数中像这样听这个通知(令牌) :

public ClientConfigView()
{
InitializeComponent();
Mediator.ListenOn(Mediator.Token.ConfigWindowShouldClose, callback => this.Close() );
}

我有以下解决方案在 Silverlight。也将在 WPF。

Childwindowext.cs :

namespace System.Windows.Controls
{
public class ChildWindowExt : ChildWindow
{
public static readonly DependencyProperty IsOpenedProperty =
DependencyProperty.Register(
"IsOpened",
typeof(bool),
typeof(ChildWindowExt),
new PropertyMetadata(false, IsOpenedChanged));


private static void IsOpenedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if ((bool)e.NewValue == false)
{
ChildWindowExt window = d as ChildWindowExt;
window.Close();
}
else if ((bool)e.NewValue == true)
{
ChildWindowExt window = d as ChildWindowExt;
window.Show();
}
}


public bool IsOpened
{
get { return (bool)GetValue(IsOpenedProperty); }
set { SetValue(IsOpenedProperty, value); }
}


protected override void OnClosing(ComponentModel.CancelEventArgs e)
{
this.IsOpened = false;
base.OnClosing(e);
}


protected override void OnOpened()
{
this.IsOpened = true;
base.OnOpened();
}
}
}

返回文章页面 ItemWindow.xaml:

<extControls:ChildWindowExt
x:Class="MyProject.ItemWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:extControls="clr-namespace:System.Windows.Controls"
Title="{Binding Title}" IsOpened="{Binding IsOpened, Mode=TwoWay}" Width="640" Height="480">


<Grid x:Name="LayoutRoot">
<Button Command="{Binding UpdateCommand}" Content="OK" Width="70" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>


</extControls:ChildWindowExt>

Itemviewmodel.cs :

private bool _IsOpened;
public bool IsOpened
{
get
{
return _IsOpened;
}
set
{
if (!Equals(_IsOpened, value))
{
_IsOpened = value;
RaisePropertyChanged("IsOpened");
}
}
}


private RelayCommand _UpdateCommand;
/// <summary>
/// Insert / Update data entity
/// </summary>
public RelayCommand UpdateCommand
{
get
{
if (_UpdateCommand == null)
{
_UpdateCommand = new RelayCommand(
() =>
{
// Insert / Update data entity
...


IsOpened = false;
},
() =>
{
return true;
});
}
return _UpdateCommand;
}
}

Itemsviewmodel.cs :

    private RelayCommand _InsertItemCommand;
/// <summary>
///
/// </summary>
public RelayCommand InsertItemCommand
{
get
{
if (_InsertItemCommand == null)
{
_InsertItemCommand = new RelayCommand(
() =>
{
ItemWindow itemWin = new ItemWindow();
itemWin.DataContext = new ItemViewModel();
itemWin.Show();


// OR


// ItemWindow itemWin = new ItemWindow();
// ItemViewModel newItem = new ItemViewModel();
// itemWin.DataContext = newItem;
// newItem.IsOpened = true;


},
() =>
{
return true;
});
}
return _InsertItemCommand;
}
}

MainPage.xaml:

<Grid x:Name="LayoutRoot">
<Button Command="{Binding InsertItemCommand}" Content="Add New" Width="70" HorizontalAlignment="Left" VerticalAlignment="Center" />
</Grid>

我祝愿你们所有好的想法和项目; -)

这可能对您有所帮助,使用 mvvm 关闭 wpf 窗口,后面的代码很少: http://jkshay.com/closing-a-wpf-window-using-mvvm-and-minimal-code-behind/

我使用 < em > 发布订阅模式 来处理复杂的类依赖关系:

视图模型:

    public class ViewModel : ViewModelBase
{
public ViewModel()
{
CloseComand = new DelegateCommand((obj) =>
{
MessageBus.Instance.Publish(Messages.REQUEST_DEPLOYMENT_SETTINGS_CLOSED, null);
});
}
}

窗口:

public partial class SomeWindow : Window
{
Subscription _subscription = new Subscription();


public SomeWindow()
{
InitializeComponent();


_subscription.Subscribe(Messages.REQUEST_DEPLOYMENT_SETTINGS_CLOSED, obj =>
{
this.Close();
});
}
}

您可以利用 Bizmonger 模式获得 MessageBus。

消息总线

public class MessageBus
{
#region Singleton
static MessageBus _messageBus = null;
private MessageBus() { }


public static MessageBus Instance
{
get
{
if (_messageBus == null)
{
_messageBus = new MessageBus();
}


return _messageBus;
}
}
#endregion


#region Members
List<Observer> _observers = new List<Observer>();
List<Observer> _oneTimeObservers = new List<Observer>();
List<Observer> _waitingSubscribers = new List<Observer>();
List<Observer> _waitingUnsubscribers = new List<Observer>();


int _publishingCount = 0;
#endregion


public void Subscribe(string message, Action<object> response)
{
Subscribe(message, response, _observers);
}


public void SubscribeFirstPublication(string message, Action<object> response)
{
Subscribe(message, response, _oneTimeObservers);
}


public int Unsubscribe(string message, Action<object> response)
{
var observers = new List<Observer>(_observers.Where(o => o.Respond == response).ToList());
observers.AddRange(_waitingSubscribers.Where(o => o.Respond == response));
observers.AddRange(_oneTimeObservers.Where(o => o.Respond == response));


if (_publishingCount == 0)
{
observers.ForEach(o => _observers.Remove(o));
}


else
{
_waitingUnsubscribers.AddRange(observers);
}


return observers.Count;
}


public int Unsubscribe(string subscription)
{
var observers = new List<Observer>(_observers.Where(o => o.Subscription == subscription).ToList());
observers.AddRange(_waitingSubscribers.Where(o => o.Subscription == subscription));
observers.AddRange(_oneTimeObservers.Where(o => o.Subscription == subscription));


if (_publishingCount == 0)
{
observers.ForEach(o => _observers.Remove(o));
}


else
{
_waitingUnsubscribers.AddRange(observers);
}


return observers.Count;
}


public void Publish(string message, object payload)
{
_publishingCount++;


Publish(_observers, message, payload);
Publish(_oneTimeObservers, message, payload);
Publish(_waitingSubscribers, message, payload);


_oneTimeObservers.RemoveAll(o => o.Subscription == message);
_waitingUnsubscribers.Clear();


_publishingCount--;
}


private void Publish(List<Observer> observers, string message, object payload)
{
Debug.Assert(_publishingCount >= 0);


var subscribers = observers.Where(o => o.Subscription.ToLower() == message.ToLower());


foreach (var subscriber in subscribers)
{
subscriber.Respond(payload);
}
}


public IEnumerable<Observer> GetObservers(string subscription)
{
var observers = new List<Observer>(_observers.Where(o => o.Subscription == subscription));
return observers;
}


public void Clear()
{
_observers.Clear();
_oneTimeObservers.Clear();
}


#region Helpers
private void Subscribe(string message, Action<object> response, List<Observer> observers)
{
Debug.Assert(_publishingCount >= 0);


var observer = new Observer() { Subscription = message, Respond = response };


if (_publishingCount == 0)
{
observers.Add(observer);
}
else
{
_waitingSubscribers.Add(observer);
}
}
#endregion
}

}

订阅

public class Subscription
{
#region Members
List<Observer> _observerList = new List<Observer>();
#endregion


public void Unsubscribe(string subscription)
{
var observers = _observerList.Where(o => o.Subscription == subscription);


foreach (var observer in observers)
{
MessageBus.Instance.Unsubscribe(observer.Subscription, observer.Respond);
}


_observerList.Where(o => o.Subscription == subscription).ToList().ForEach(o => _observerList.Remove(o));
}


public void Subscribe(string subscription, Action<object> response)
{
MessageBus.Instance.Subscribe(subscription, response);
_observerList.Add(new Observer() { Subscription = subscription, Respond = response });
}


public void SubscribeFirstPublication(string subscription, Action<object> response)
{
MessageBus.Instance.SubscribeFirstPublication(subscription, response);
}
}

我认为最简单的方法还没有被包括在内(几乎)。不要使用添加新依赖项的行为,而是使用附加属性:

    using System;
using System.Windows;
using System.Windows.Controls;


public class DialogButtonManager
{
public static readonly DependencyProperty IsAcceptButtonProperty = DependencyProperty.RegisterAttached("IsAcceptButton", typeof(bool), typeof(DialogButtonManager), new FrameworkPropertyMetadata(OnIsAcceptButtonPropertyChanged));
public static readonly DependencyProperty IsCancelButtonProperty = DependencyProperty.RegisterAttached("IsCancelButton", typeof(bool), typeof(DialogButtonManager), new FrameworkPropertyMetadata(OnIsCancelButtonPropertyChanged));


public static void SetIsAcceptButton(UIElement element, bool value)
{
element.SetValue(IsAcceptButtonProperty, value);
}


public static bool GetIsAcceptButton(UIElement element)
{
return (bool)element.GetValue(IsAcceptButtonProperty);
}


public static void SetIsCancelButton(UIElement element, bool value)
{
element.SetValue(IsCancelButtonProperty, value);
}


public static bool GetIsCancelButton(UIElement element)
{
return (bool)element.GetValue(IsCancelButtonProperty);
}


private static void OnIsAcceptButtonPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
Button button = sender as Button;


if (button != null)
{
if ((bool)e.NewValue)
{
SetAcceptButton(button);
}
else
{
ResetAcceptButton(button);
}
}
}


private static void OnIsCancelButtonPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
Button button = sender as Button;


if (button != null)
{
if ((bool)e.NewValue)
{
SetCancelButton(button);
}
else
{
ResetCancelButton(button);
}
}
}


private static void SetAcceptButton(Button button)
{
Window window = Window.GetWindow(button);
button.Command = new RelayCommand(new Action<object>(ExecuteAccept));
button.CommandParameter = window;
}


private static void ResetAcceptButton(Button button)
{
button.Command = null;
button.CommandParameter = null;
}


private static void ExecuteAccept(object buttonWindow)
{
Window window = (Window)buttonWindow;


window.DialogResult = true;
}


private static void SetCancelButton(Button button)
{
Window window = Window.GetWindow(button);
button.Command = new RelayCommand(new Action<object>(ExecuteCancel));
button.CommandParameter = window;
}


private static void ResetCancelButton(Button button)
{
button.Command = null;
button.CommandParameter = null;
}


private static void ExecuteCancel(object buttonWindow)
{
Window window = (Window)buttonWindow;


window.DialogResult = false;
}
}

然后把它设置在你的对话框按钮上:

<UniformGrid Grid.Row="2" Grid.Column="1" Rows="1" Columns="2" Margin="3" >
<Button Content="Accept" IsDefault="True" Padding="3" Margin="3,0,3,0" DialogButtonManager.IsAcceptButton="True" />
<Button Content="Cancel" IsCancel="True" Padding="3" Margin="3,0,3,0" DialogButtonManager.IsCancelButton="True" />
</UniformGrid>

我在这个主题上纠结了一段时间,最终采用了与 MVVM 一致的最简单的方法: 让按钮执行完成所有繁重工作的 Command,并让按钮的 Click 处理程序关闭窗口。

XAML

<Button x:Name="buttonOk"
Click="closeWindow"
Command="{Binding SaveCommand}" />

XAML.cs

public void closeWindow()
{
this.DialogResult = true;
}

拯救指挥官

 // I'm in my own file, not the code-behind!

诚然,仍然存在代码隐藏,但这本身并没有什么坏处。从面向对象的角度来看,让窗口自动关闭对我来说最有意义。

没有代码,你也可以做到。创建命令,在视图模型上执行方法调用“ Save”方法,在编辑窗口上调用 close 方法之后,可以通过参数传递给命令:

public void Execute(object parameter)
{
_mainViewModel.SaveSomething();
var editWindow = parameter as MyEditWindow;
editWindow?.Close();
}

保存和关闭按钮 XAML:

<Button Content"Save&Close" Command="{Binding SaveCmd}" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"  IsDefault="True" />

非常干净和 MVVM 的方式是使用 InteractionTriggerCallMethodAction定义在 Microsoft.Interactivity.Core

您将需要添加一个新的名称空间,如下所示

xmlns:i="http://schemas.microsoft.com/xaml/behaviors"

您将需要 微软。 Xmal。行为程序集,然后下面的 xaml 代码将工作。

<Button Content="Save" Command="{Binding SaveCommand}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:CallMethodAction MethodName="Close"
TargetObject="{Binding RelativeSource={RelativeSource
Mode=FindAncestor,
AncestorType=Window}}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>

您不需要后面的任何代码或其他任何东西,也可以调用 Window的任何其他方法。

在. xaml 定义中有 name 属性:

x:Name="WindowsForm"

然后我们有了按钮:

<Button Command="{Binding CloseCommand}"
CommandParameter="{Binding ElementName=WindowsForm}" />

然后在 ViewModel 中:

public DelegateCommand <Object>  CloseCommand { get; private set; }


Constructor for that view model:
this.CloseCommand = new DelegateCommand<object>(this.CloseAction);

最后,行动方法:

private void CloseAction (object obj)
{
Window Win = obj as Window;
Win.Close();


}

我用这段代码关闭了一个应用程序的弹出窗口。

我也不得不处理这个问题,所以这里我的解决方案。它对我很有效。

1. 创建类 RegiateCommand

    public class DelegateCommand<T> : ICommand
{
private Predicate<T> _canExecuteMethod;
private readonly Action<T> _executeMethod;
public event EventHandler CanExecuteChanged;


public DelegateCommand(Action<T> executeMethod) : this(executeMethod, null)
{
}
public DelegateCommand(Action<T> executeMethod, Predicate<T> canExecuteMethod)
{
this._canExecuteMethod = canExecuteMethod;
this._executeMethod = executeMethod ?? throw new ArgumentNullException(nameof(executeMethod), "Command is not specified.");
}




public void RaiseCanExecuteChanged()
{
if (this.CanExecuteChanged != null)
CanExecuteChanged(this, null);
}
public bool CanExecute(object parameter)
{
return _canExecuteMethod == null || _canExecuteMethod((T)parameter) == true;
}


public void Execute(object parameter)
{
_executeMethod((T)parameter);
}
}

2. 定义你的命令

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




public MyViewModel()//ctor of your viewmodel
{
//do something


CloseWindowCommand = new DelegateCommand<Window>(CloseWindow);




}
public void CloseWindow(Window win) // this method is also in your viewmodel
{
//do something
win?.Close();
}

3. 在视图中绑定命令

public MyView(Window win) //ctor of your view, window as parameter
{
InitializeComponent();
MyButton.CommandParameter = win;
MyButton.Command = ((MyViewModel)this.DataContext).CloseWindowCommand;
}

4. 现在是窗户

  Window win = new Window()
{
Title = "My Window",
Height = 800,
Width = 800,
WindowStartupLocation = WindowStartupLocation.CenterScreen,


};
win.Content = new MyView(win);
win.ShowDialog();

因此,您还可以绑定 xaml 文件中的命令,并使用 Find始祖查找窗口,并将其绑定到 command 参数。

在 wpf 中关闭一个窗口的解决方案对我来说是有效的,但是这里没有回答,所以我想我也应该添加我的解决方案。

        private static Window GetWindow(DependencyObject sender)
{
Window window = null;
if (sender is Window)
window = (Window)sender;
if (window == null)
window = Window.GetWindow(sender);
return window;
}
private void CloseWindow(object sender, RoutedEventArgs e)
{
var button = (Button)sender as DependencyObject;


Window window = GetWindow(button);
if (window != null)
window.Close();
// window.Visibility = Visibility.Hidden;
// choose between window.close or set window.visibility to close or hide the window.


//            }
}


向窗口中的按钮添加 CloseWindow 事件,如下所示。

<Button Content="Cancel" Click="CloseWindow" >

我发现自己不得不在一个基于。Net Core 3.0,遗憾的是,在 微软。 Xaml。行为 NuGet 包中还没有正式提供行为支持。

相反,我使用了一个利用了 Façade 设计模式的解决方案。

界面:

public interface IWindowFacade
{
void Close();
}

窗口:

public partial class MainWindow : Window, IWindowFacade
…

视图模型上的标准命令属性:

public ICommand ExitCommand
…

控件绑定:

<MenuItem Header="E_xit" Command="{Binding ExitCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window}}"/>

命令:

public class ExitCommand : ICommand
{
…
public void Execute(object parameter)
{
var windowFacade = parameter as IWindowFacade;
windowFacade?.Close();
}
…
}

因为 Close()方法已经由 Window类实现,所以将 facade 接口应用到窗口是 UI 层中唯一需要的代码(对于这个简单的示例)。表示层中的命令避免了对视图/UI 层的任何依赖,因为当它在外观上调用 Close方法时,它不知道自己在与什么对话。

在当前窗口 xaml.cs文件中,调用以下代码:

var curWnd = Window.GetWindow(this); // passing current window context
curWnd?.Close();

这个应该可以了。
这对我有用,希望对你也一样)

简单的方法是关闭 saveComand 实现窗口。 使用以下代码关闭窗口。

Application.Current.Windows[1].Close();

它会关闭子窗口。

没有任何依赖性。

<Window ...>
...
<Button Command="{x:Static SystemCommands.CloseWindowCommand}" />
</Window>