【问题标题】:Creating dialog windows with Dependency Injection and Services使用依赖注入和服务创建对话窗口
【发布时间】:2021-06-03 13:29:13
【问题描述】:

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

我还在这里读到,在仍然遵循 MVVM 的同时使用对话窗口的一种方法是拥有一个服务,该服务将创建一个具有动态填充视图模型的对话窗口容器。

到目前为止,一切都很好。但是我遇到了一个障碍: 我在我的 MainView 上,我运行一个打开一个新对话框窗口的命令(我认为是一个新的范围)。在 that 对话框中,我运行了一个应该打开 another 对话框窗口的命令。但是,当试图关闭时,我设法关闭了父对话框而不是焦点窗口。我的相关代码如下:

我在这里做错了什么?

PS.:为了更好的可读性,我将名称翻译成英文,但我可能会漏掉一个或另一个 - 如果我能解决任何问题,请告诉我。

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);
    }

【问题讨论】:

    标签: c# mvvm dependency-injection entity-framework-core


    【解决方案1】:

    我找到了解决方法。看了Good or bad practice for Dialogs in wpf with MVVM?之后找到了答案。

    我创建了一个单例dialogStore,其中保留了所有当前打开的对话框。每当我需要一个新的对话窗口时,我都会用dialogStore“注册”一个新的dialogGenerator,它会为我打开它。当我需要关闭它时,商店也负责。此外,到目前为止,我一次只使用一个处于活动状态的模态对话框,所以每当我关闭一个对话框时,我都会确定它是最新添加的一个。但在未来,每个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,因此我仍然需要在删除之前从dialogGenerator 中的任何内容中处理它来自我的dialogStore

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-01-02
      • 1970-01-01
      • 2012-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-09
      相关资源
      最近更新 更多