用依赖注入和服务创建对话窗口



我终于屈服了,开始在我的EFCore项目上学习和应用MVVM架构。但是,我还不了解作用域服务是如何工作的。在我之前的问题上,我被告知我需要为每个视图模型使用一个作用域,否则,因为我正在使用异步方法,我将在相同的DbContext上获得并发事务(这是不允许的)。

我也在这里读到,使用对话框窗口的一种方式,而仍然遵循MVVM将有一个服务,将创建一个对话框窗口容器与动态填充的视图模型。

到目前为止,一切顺利。然而,我遇到了一个障碍:我在我的主视图上,我运行一个命令,打开一个新的对话框窗口(有一个新的范围,我认为)。在那个对话框中,我运行一个命令,应该会打开另一个对话框窗口。然而,当试图关闭时,不知何故,我设法关闭父对话框而不是聚焦窗口。我的相关代码如下:

我在这里做错了什么?

p。:为了更好的可读性,我把名字翻译成了英文,但我可能漏掉了一个或另一个,如果我能修改什么,请告诉我。

public class PurchasesViewModel : ViewModelBase
{
private readonly IDialogGenerator _purchaseDialogGenerator;
private readonly IDialogViewModelFactory _purchaseRecordVMFactory;
public ICommand CreateNewPurchase { get; set; }
public PurchasesViewModel(IServiceProvider services, IDialogGenerator purchaseVMDialogGenerator)
{
_purchaseDialogGenerator = purchaseVMDialogGenerator;
IServiceScope purchaseVMScope = services.CreateScope();
IServiceProvider provider = purchaseVMScope.ServiceProvider;
_purchaseRecordVMFactory = provider.GetRequiredService<IDialogViewModelFactory>();
CreateNewPurchase = new CreatePurchaseCommand(_purchaseDialogGenerator, _purchaseRecordVMFactory);
}
}
internal class CreatePurchaseCommand : ICommand
{
private IDialogGenerator _purchaseDialogGenerator;
private IDialogViewModelFactory _purchaseVMFactory;
public CreatePurchaseCommand(IDialogGenerator PurchaseRecordDialogGenerator, IDialogViewModelFactory PurchaseRecordVMFactory)
{
_purchaseDialogGenerator = PurchaseRecordDialogGenerator;
_purchaseVMFactory = PurchaseRecordVMFactory;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
_purchaseDialogGenerator.ShownViewModel = _purchaseVMFactory.CreateDialogContentViewModel(DialogType.RecordPurchases);
_purchaseDialogGenerator.ShowDialog();
}
}
public class PurchaseRecordViewModel : DialogContentViewModelBase
{
private readonly IMessaging<PURCHASE> _purchaseMessaging;
private readonly IDialogGenerator _purchaseDialogGenerator;
private readonly IDialogGenerator _importViaXMLDialogGenerator;
private readonly IDialogViewModelFactory _importViaXMLVMFactory;

public ICommand SavePurchase { get; set; }
public ICommand ImportXML { get; set; }
public PurchaseRecordViewModel(IServiceProvider servicos, IDialogGenerator PurchaseRecordDialogGenerator)
{
_purchaseDialogGenerator = PurchaseRecordDialogGenerator;
IServiceScope scope = servicos.CreateScope();
IServiceProvider provider = scope.ServiceProvider;
_importViaXMLDialogGenerator = provider.GetRequiredService<IDialogGenerator>();
_importViaXMLVMFactory = provider.GetRequiredService<IDialogViewModelFactory>();
_purchaseMessaging = provider.GetRequiredService<IMessaging<PURCHASE>>();
SavePurchase = new SalvaPurchaseCommandAsync(PurchaseRecordDialogGenerator);
ImportXML = new ImportXMLDePurchaseCommand(_importViaXMLDialogGenerator, _importViaXMLVMFactory);
}
}
internal class ImportXMLFromPurchaseCommand : ICommand
{
private readonly IDialogGenerator _importviaXMLDialogGenerator;
private readonly IDialogViewModelFactory _importXMLVMFactory;
public ImportXMLFromPurchaseCommand(
IDialogGenerator importviaXMLDialogGenerator,
IDialogViewModelFactory importXMLVMFactory)
{
_importviaXMLDialogGenerator = importviaXMLDialogGenerator;
_importXMLVMFactory = importXMLVMFactory;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
_importviaXMLDialogGenerator.ShownViewModel = _importXMLVMFactory.CreateDialogContentViewModel(DialogType.ImportXML);
_importviaXMLDialogGenerator.ShowDialog();
}
}
internal class SalvaPurchaseCommandAsync : ICommand
{
private readonly IDialogGenerator _dialogGenerator;
public SalvaPurchaseCommandAsync(IDialogGenerator dialogGenerator)
{
_dialogGenerator = dialogGenerator;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
_dialogGenerator.Result = DialogResult.OK;
_dialogGenerator.Close();
}
}
public class ImportViaXMLViewModel : DialogContentViewModelBase
{
public ICommand ImportArquivoXML { get; set; }
public ICommand Import { get; set; }

private readonly IDialogGenerator _importViaXMLDialogGenerator;

public ImportViaXMLViewModel(IMessaging<PURCHASE> messaging, 
IDialogGenerator importViaXMLDialogGenerator)
{
_importViaXMLDialogGenerator = importViaXMLDialogGenerator;
Import = new ImportCommand(this, messaging, _importViaXMLDialogGenerator);
}
}
internal class ImportCommand : ICommand
{
private readonly IMessaging<PURCHASE> _messaging;
private readonly IDialogGenerator _dialogGenerator;
public ImportCommand(IMessaging<PURCHASE> messaging, IDialogGenerator dialogGenerator)
{
_messaging = messaging;
_dialogGenerator = dialogGenerator;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
_messaging.Message = new COMPRA();
_dialogGenerator.Result = DialogResult.OK;
_dialogGenerator.Close();
}
}
public abstract class AsyncCommandBase : ICommand
{
private bool _isExecuting;
private readonly Action<Exception> _onException;
public bool IsExecuting
{
get { return _isExecuting; }
set {
_isExecuting = value;
CanExecuteChanged?.Invoke(this, new EventArgs());
}
}
public AsyncCommandBase(Action<Exception> onException)
{
this._onException = onException;
}
public virtual event EventHandler CanExecuteChanged;
public virtual bool CanExecute(object parameter)
{
return !IsExecuting;
}
public async void Execute(object parameter)
{
IsExecuting = true;
try
{
await ExecuteAsync(parameter);
}
catch (Exception ex)
{
_onException(ex);
}
IsExecuting = false;
}
protected abstract Task ExecuteAsync(object parameter);
}

我找到了一个解决办法。我在阅读了MVVM中wpf对话框的好与坏实践后找到了答案。

我已经创建了一个单例dialogStore,其中我保留了所有当前打开的对话框。每当我需要一个新的对话框窗口时,我都会"注册"。一个新的dialogGeneratordialogStore,它会为我打开它。当我需要关门的时候,商店也要负责。此外,到目前为止,我一次只使用一个活动的模态对话框,所以每当我关闭一个对话框时,我将确保它是最新添加的一个。但是在未来,每个dialogGenerator将知道它的dialogStore索引集,并且将能够以任何需要的顺序关闭它们自己(和其他对话框)。

我的dialogStore如下:

public class DialogsStore : IDialogsStore
{
public List<IDialogGenerator> OpenDialogs { get; set; } = new List<IDialogGenerator>();
public void CloseDialog(DialogResult dialogResult)
{
IDialogGenerator lastDialogGenerator = OpenDialogs[OpenDialogs.Count - 1];
lastDialogGenerator.Resultado = dialogResult;
//lastDialogGenerator.DialogClosed = null;
lastDialogGenerator.Close();
}
public int RegisterDialog(IDialogGenerator dialog)
{
OpenDialogs.Add(dialog);
dialog.DialogClosed += Dialog_DialogClosed;
dialog.ShowDialog();
return OpenDialogs.Count - 1;
}
private void Dialog_DialogClosed()
{
OpenDialogs.RemoveAt(OpenDialogs.Count - 1);
}
}

我必须处理的一个重要问题是,关闭对话框并将其从存储中删除并没有处理作用域dialogGenerator,所以我仍然需要在从dialogStore中删除它之前处理dialogGenerator中的任何内容。

如果有人有更好的方法来处理MVVM中的依赖注入对话框窗口,我将很高兴听到它。

最新更新