我是.NET MVVM应用程序结构的新手,并且只是基本知识它的原理,如解耦,绑定,命令等。我使用MVVM Light框架来简化常见MVVM问题如消息和服务位置。
我不明白的一件事:每次使用ViewModel的Model类时,是否需要调用SimpleIoC?
例:
我有一个简单的View,一个与之对应的ViewModel和一个具有一个类Settings
的模型。
MainWindow.xaml
<Window ...>
<Window.Resources>
<viewModels:MainWindowModel x:Key="ViewModel" />
</Window.Resources>
<DockPanel DataContext="{StaticResource ViewModel}">
<Button Command="{Binding DoSomeCommand}" />
</DockPanel>
</Window>
MainWindowModel.cs
public class MainWindowModel: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public ICommand DoSomeCommand { get; private set; }
protected void RaisePropertyChangedEvent(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public MainWindowModel()
{
DoSomeCommand = new RelayCommand(DoSome);
}
public void DoSome()
{
var data = Settings.Instance; //singleton
//... do some with data ...
Debug.Log($"{data.Prop1}, {data.Prop2}, {data.Prop3}");
}
}
Settings.cs
public static class Settings
{
//... singleton implementations ...
public int Prop1 { get; set; } // implementation of getters and setters
public int Prop2 { get; set; }
public int Prop3 { get; set; }
}
此代码有一个巨大的缺点:DoSome()
方法不是单元可测试的。好的,让我们解决一下:
public class MainWindowModel: INotifyPropertyChanged
{
//...
private Settings _data;
public MainWindowModel()
{
_data = Settings.Instance;
DoSomeCommand = new RelayCommand(() => DoSome(_data));
}
public void DoSome(Settings data)
{
//... do some with data ...
Debug.Log($"{data.Prop1}, {data.Prop2}, {data.Prop3}");
}
}
现在我可以模拟或存根Settings
类并测试DoSome()
。
但我知道&#39;设置&#39; class可以在不同的实现中,例如&#39; SettingsXML&#39; (XML的数据),&#39; SettingsRegistry&#39; (Window Registry的数据),&#39; SettingsINI&#39; (来自INI文件的数据,很奇怪,但确实如此)。为了避免潜在的问题,我在接口中重写了它:
public interface ISettings
{
public int Prop1;
public int Prop2;
public int Prop3;
}
public static class Settings: ISettings
{
//... singleton implementations ...
public int Prop1 { get; set; } // implementation of getters and setters
public int Prop2 { get; set; }
public int Prop3 { get; set; }
}
public class MainWindowModel: INotifyPropertyChanged
{
//...
private ISettings _data;
public void DoSome(ISettings data)
{
... do some with data ...
Debug.Log($"_data.Prop1}, {data.Prop2}, {data.Prop3}");
}
}
一切看起来都不错。 DoSome()
是可测试的,Settings
实现可能不同。有一件事困扰我:MainWindowModel
知道实际的设置类别(_data = Settings.Instance
)。
MVVM结构可以吗?
是否真的有必要使用一些IoC,写一些&#39; SettingsWrapper&#39;依赖注入ISettings类的类,然后使用_data = SimpleIoc.Default.GetInstance<SettingsWrapper>
?
如果Settings
课程不是单身人士,我该怎么做?
很抱歉,如果我对DI和IoC的基本概念完全错误的话。如果你能纠正我,我将不胜感激。
答案 0 :(得分:1)
有一件事困扰我:
MainWindowModel
知道实际的设置类别(_data = Settings.Instance
)。
不应该。它应该只知道它正在注入的接口。
您可以在创建ISettings
类本身时使用DoSome
注入MainWindowModel
类,而不是将ISettings
对象传递给public MainWindowModel(ISettings settings) { ... }
方法:
ViewModelLocator
然后您可以让public class ViewModelLocator
{
public ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<ISettings>(() => Settings.Instance);
SimpleIoc.Default.Register<MainViewModel>();
}
public MainViewModel Main
{
get
{
return ServiceLocator.Current.GetInstance<MainViewModel>();
}
}
}
负责创建视图模型类:
<DockPanel DataContext="{Binding Main, Source={StaticResource Locator}}">
<Button Command="{Binding DoSomeCommand}" />
</DockPanel>
@wrapper