我的ViewModel
上有以下代码段,我想摆脱new
关键字,将创建责任交给DI容器。但是,由于给定的参数IDataFileReader
与ViewModel
progress
属性有关,因此我难以将ViewModel
注入我的ProgressBarValue
中。
基本上,我的文件阅读器需要进度作为参数,以便我可以在UI上显示进度。
所以问题是,如何在
IDataFileReader
上向AutoFac模块注册ViewModelLocator
?
VieModel.cs
ProgressBarIsIndetermined = true;
var progress = new Progress<int>(status => { ProgressBarValue = status; });
await Task.Run(() =>
{
IDataFileReader fileImporter = new DataFileReader(progress);
DataSet = new ObservableCollection<MeasurementPoint>(fileImporter.DataSet);
});
我正在将Mvvm Light viewmodelLocator
和MVVM与WPF一起使用。对于不需要任何参数的简单服务,我可以通过构造函数注入轻松实现。
ViewModelLocator.cs
static ViewModelLocator()
{
var builder = new ContainerBuilder();
builder.RegisterModule<AutofacModule>();
var container = builder.Build();
ServiceLocator.SetLocatorProvider(() => new AutofacServiceLocator(container));
}
public SettingsViewModel SettingsViewModel => ServiceLocator.Current.GetInstance<SettingsViewModel>();
AutoFacModule.cs
以下模块只是一个草稿,可以在没有参数的情况下进行简单的构造函数注入。
public class AutofacModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<DataFileReader>().As<IDataFileReader>();
builder.RegisterType<SettingsViewModel>().AsSelf().SingleInstance();
}
}
答案 0 :(得分:1)
基本上,您不能以很好的方式做到这一点:)您首先应该问自己,DataFileReader
为什么关心进度。也许还有其他事情应该观察进展并将其报告给全世界?
我还建议避免使用ServiceLocator模式。类应仅包含通过构造函数显式注入的定义明确的依赖项。我认为,属性注入也应视为反模式。
答案 1 :(得分:1)
您想要的是DataFileReader
更新ViewModel的ProgressBarValue
属性。最简单的方法是在OnUpdate
DataFileReader
方法
reader.OnUpdate(status => this.ProgressBarValue = status.PercentProgress);
通过这样做,您将向您的IDataFileReader
界面添加一个可能不合适的新职责,并破坏Single Responsibility Principle。
在这种情况下,通常会引入一个只关注一件事的新组件。
public interface IProgressObserver
{
void OnUpdate(Action<Int32> updater);
void Update(Int32 percent);
}
您的DataFileReader
可以依赖此组件,并在需要时调用Update
方法。您的ViewModel将具有IProgressObserver
依赖性和IDataFileReader
IProgressObserver
的一种可能实现就像
public class ProgressObserver : IProgressObserver
{
private Action<Int32> _updater = _ => { };
public void Update(Int32 percent)
{
this._updater(percent);
}
public void Register(Action<Int32> updater)
{
this._updater = updater;
}
}
答案 2 :(得分:1)
另一种选择是注入一个可以创建IDataFileReader
的委托,而不是已经实例化的委托。这将使您可以将Progress
对象传递给它。
Autofac支持delegate factories。这可能会导致如下所示(未经测试):
public class DataFileReader : IDataFileReader
{
public delegate DataFileReader Factory(Progress progress);
public Shareholding(Progress progress)
{
Progress = progress;
}
}
public class ViewModel
{
private readonly DataFileReader.Factory factory;
public ViewModel(DataFileReader.Factory dataFileReaderFactory)
{
factory = dataFileReaderFactory;
}
...
IDataFileReader fileImporter = factory(progress);
}