在WPF C#应用程序的Window类之外使用.base属性的OnClosed()方法

在WPF C#应用程序的Window类之外使用.base属性的OnClosed()方法,c#,wpf,C#,Wpf,我创建了一个ICommand,除了执行一些SQL过程外,它还检查在SQL过程执行时主窗口UI是否已关闭。如果用户关闭了主窗口,我希望应用程序通过使用属性return停止 我的问题是ICommand在MVVM模型中。这个MVVM模型在主窗口(窗口类)之外。因此,当我尝试调用base.OnClosed时,我得到一个错误,由于它的保护级别(窗口方法是受保护的或私有的),我无法访问它 我的代码实现是什么样子的: 命名空间项目 { class ClosedClass//我将其转换为一个类,因为无法在窗口类

我创建了一个ICommand,除了执行一些SQL过程外,它还检查在SQL过程执行时主窗口UI是否已关闭。如果用户关闭了主窗口,我希望应用程序通过使用属性
return停止

我的问题是ICommand在MVVM模型中。这个MVVM模型在主窗口(窗口类)之外。因此,当我尝试调用
base.OnClosed
时,我得到一个错误,由于它的保护级别(窗口方法是受保护的或私有的),我无法访问它

我的代码实现是什么样子的:

命名空间项目
{
class ClosedClass//我将其转换为一个类,因为无法在窗口类之外访问方法
{
公共布尔是封闭的{get;private set;}
关闭时受保护的覆盖无效(事件参数e)
{
base.OnClosed(e);//错误:对象不包含“OnClosed”的定义
//(方法2)MainWindow.OnClosed(e);//错误:由于其保护级别,无法访问
IsClosed=true;
}
}
公共类MainWindowViewModel:INotifyPropertyChanged
{
公共ICommand运行命令
{
获取{重新运行新的DelegateCommand(FuncRunCommand);)
}
公共异步void FuncRunCommand(对象参数)
{
wait Task.Run(()=>RunCustomMetod());//此方法中包含IsClosed语句
}
public void RunCustomMetod()
{
if(IsClosed)//错误:名称“IsClosed”在当前上下文中不存在
{
return;//如果IsClose为true,则停止执行RunCustomMetod()
}
}
}
公共部分类主窗口:窗口
{
//... 
}
}
根据我对类似问题所做的一些研究,我发现了这两个答案:

然而,我对C#的缺乏经验并没有帮助我理解如何解决我的问题,即使答案很清楚。有什么建议吗?我感谢您提前花时间和精力

[更新——基于评论]

命名空间项目
{
公共类MainWindowViewModel:INotifyPropertyChanged
{
公共布尔是封闭的{get;private set;}
受保护的重写void OnClosed(EventArgs e)//1.错误:MainWindowViewModel.OnClosed(EventArgs)':找不到合适的重写方法
{
MainWindow.OnClosed(e)//2.Error:由于其保护级别而无法访问
((MainWindowViewModel)DataContext).IsClosed=true;//3.Error:“DataContext”在当前上下文中不存在。
}
公共ICommand运行命令
{
获取{重新运行新的DelegateCommand(FuncRunCommand);)
}
公共异步void FuncRunCommand(对象参数)
{
wait Task.Run(()=>RunCustomMetod());//此方法中包含IsClosed语句
}
public void RunCustomMetod()
{
if(IsClosed)//错误:名称“IsClosed”在当前上下文中不存在
{
return;//如果IsClose为true,则停止执行RunCustomMetod()
}
}
}
公共部分类主窗口:窗口
{
//... 
}
}

这是MVVM,因此您不希望视图模型关心UI的任何状态。此外,您永远不希望视图模型依赖于视图类中定义的方法。
如果视图模型依赖于属性,请使用数据绑定将值发送到视图模型,但避免仅为了观察视图而引入属性(因为这在大多数情况下是对糟糕设计的提示)

显然,您真正想要的是允许视图根据UI状态或用户交互取消正在执行的命令(或者更准确地说是后台线程)

在这种情况下,推荐的方法是使用简单的
任务

当窗口关闭时,您将调用
CancellationTokenSource.Close()
方法。通常,所有任务库API方法都支持取消。只需选择接受对
Cancellationtoken
引用的适当重载即可

要为自定义方法提供取消机制,只需传递对实际
CancellationToken
(由and调用
CancellationToken.throwifccancellationrequested()创建)的引用
若调用了
CancellationTokenSource.Close()
,则使
CancellationToken
抛出
操作CancelleException
(或者轮询
CancellationToken.IsCancellationRequested
):

MainViewModel.cs

public class MainViewModel : INotifyProeprtyChanged
{
  public MainViewModel()
  {
    this.CancellationTokenSource = new CancellationTokenSource();
  }

  private void CancelSql(object obj)
  {
    this.CancellationTokenSource?.Cancel();
  }

  private async void ExecuteSqlAsync(object obj)
  {
    // The complete Task API accepts a CancellationToken to allow cancellation.
    try
    {
      await Task.Run(() => RunCustomMethod(this.CancellationTokenSource.Token), this.CancellationTokenSource.Token);
    }
    catch (OperationCanceledException e)
    {
      // Do some optional cleanup before recovering from the exception

      // Once cancelled, we have to use a new CancellationTokenSource instance. 
      // But first, we have to dispose the old one
      this.CancellationTokenSource.Dispose();
      this.CancellationTokenSource = new CancellationTokenSource();
    }
  }

  private void RunCustomMethod(CancellationToken cancellationToken)
  {
    // Test if operation has already been cancelled.
    // This stops the execution of the current method, if the CancelSqlCommand was executed.
    cancellationToken.ThrowIfCancellationRequested();

    // Continue execution. Periodically call cancellationToken.ThrowIfCancellationRequested()
    // whenever possible to allow cancellation of the current operation.

    // Dummy loop to create a executable example
    while (true)
    {
      // Periodically check if the operation has been cancelled
      cancellationToken.ThrowIfCancellationRequested();
    }
  }

  public ICommand AbortSqlCommand => new DelegateCommand<object>(CancelSql);
  public ICommand ExecuteSqlCommand => new DelegateCommand<object>(ExecuteSqlAsync);
  private CancellationTokenSource CancellationTokenSource { get; set; }
}
public partial class SomeWindow : Window
{
  public SomeWindow()
  {
    InitializeComponent();

    this.DataContext = new MainViewModel();
    this.Closing += CancelSqlOperationsOnClosing;
  }

  private void CancelSqlOperationsOnClosing(object sender, CancelEventArgs e)
  {
    if (this.DataContext is MainViewModel viewModel)
    {
      viewModel.AbortSqlCommand.Execute(string.Empty);
    }
  }
}

不是根据纯MVV;原则,但您可以在
MainWindow.OnClosed
((MainWindowViewModel)DataContext)中执行以下操作.IsClosed=true;
根据您的方法查看此@KlausGütter
DataContext
未定义,因此我得到一个错误。您的答案是否需要更完整的内容?@apomene我以前搜索过这篇文章,但是,我不想在
main window()中调用
Closing
事件
class。我希望MVVM模型中的自定义方法调用它。我是否错过了您发布的链接中的某些内容?如果是这样,如果您发布基于我的代码的答案,它将真正帮助我。我希望MVVM模型中的自定义方法调用它[关闭事件]这没有意义,事件是由用户操作引发的,而不是由模型引发的。感谢您的回答Bionic。Breifly,我想检查窗口是否关闭。如果是,请按照您的暗示终止异步任务。我将检查您的回答,并让您知道我理解了您的观点