统一及;WPF-通过属性注入将DataContext注入子控件
我遵循Jason Dollinger的MVVM示例,从中学习将Unity与MVVM WPF应用程序结合使用的基础知识。我按照他的基本架构构建了一个简单的示例,使用属性注入和依赖属性将viewmodels注入到视图中。我的示例有一个主窗口,在该窗口的XAML中创建了一个子用户控件。子控件(以及主窗口)具有用于指定viewmodel的属性:统一及;WPF-通过属性注入将DataContext注入子控件,wpf,dependency-injection,unity-container,Wpf,Dependency Injection,Unity Container,我遵循Jason Dollinger的MVVM示例,从中学习将Unity与MVVM WPF应用程序结合使用的基础知识。我按照他的基本架构构建了一个简单的示例,使用属性注入和依赖属性将viewmodels注入到视图中。我的示例有一个主窗口,在该窗口的XAML中创建了一个子用户控件。子控件(以及主窗口)具有用于指定viewmodel的属性: [Dependency] public IChildViewModel VM { set { this.DataContext = value;} }
[Dependency]
public IChildViewModel VM
{
set { this.DataContext = value;}
}
我在app.xaml.cs中连接所有内容:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
IUnityContainer container = new UnityContainer();
container.RegisterType<IWindowViewModel, Window1ViewModel>();
container.RegisterType<IChildViewModel, UserControl1ViewModel>();
Window1 window = container.Resolve<Window1>();
window.Show();
}
启动时受保护的覆盖无效(StartupEventArgs e)
{
基础。启动时(e);
IUnityContainer容器=新的UnityContainer();
container.RegisterType();
container.RegisterType();
Window1 window=container.Resolve();
window.Show();
}
主窗口正在注入其viewmodel,但子控件没有。有没有任何直接的方法可以让解析向下传播到子控件中?要做到这一点,我需要做什么样的架构更改?目前我还不太喜欢Unity,因此如果支持这种行为,我可以换成另一个容器。如果我将我的子视图模型合并为窗口的viewmodel上的属性并公开为属性,然后将XAML中用户控件的DataContext设置为适当的属性,然后,我可以从子代码中完全删除依赖属性属性。不过,它会形成一种笨重的窗口视图模型。我对此并不完全满意。我从answer to.中得出了这种方法。答案取决于主窗口是作为复合视图“拥有”子窗口,还是动态创建新视图(对于模式或非模式子窗口) 在第一种情况下,主视图模型必须直接拥有子视图模型,这意味着您可以在主视图模型上将子视图模型实现为只读属性,并使用数据绑定将子视图绑定到相应的属性 要让主ViewModel直接控制子对象的创建,还是使用构造函数注入将子对象注入其中,取决于所需的可变性程度 与往常一样,如果您需要在任意时间创建子视图的新实例,则插入的抽象工厂是更好的模型
例如,我经常定义此接口并将其注入需要它的ViewModels中:
public interface IWindow
{
void Close();
IWindow CreateChild(object viewModel);
void Show();
bool? ShowDialog();
}
这允许ViewModel创建新窗口并显示它们(例如,作为对话框)。一个简单的实现如下所示:
public class WindowAdapter : IWindow
{
private readonly Window window;
public WindowAdapter(Window window)
{
if (window == null)
{
throw new ArgumentNullException("window");
}
this.window = window;
}
#region IWindow Members
public void Close()
{
this.window.Close();
}
public IWindow CreateChild(object viewModel)
{
var cw = new ContentWindow();
cw.Owner = this.window;
cw.WindowStartupLocation = WindowStartupLocation.CenterOwner;
cw.DataContext = viewModel;
return cw;
}
public void Show()
{
this.window.Show();
}
public bool? ShowDialog()
{
return this.window.ShowDialog();
}
#endregion
}
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
UnityContainer unityContainer = new UnityContainer();
this.Properties["UnityContainer"] = unityContainer;
unityContainer.LoadConfiguration();
unityContainer.Resolve<MainWindow>().Show();
}
public static IUnityContainer UnityContainer
{
get
{
return (IUnityContainer)App.Current.Properties["UnityContainer"];
}
}
我还一直在为将DataContext注入视图(UserControls)的概念而挣扎。
通过主窗口viewmodel公开子视图模型的想法吸引力有限 以下想法可行,但您确实从VisualStudioIDE得到了负面反馈 我的App.xaml.cs如下所示:
public class WindowAdapter : IWindow
{
private readonly Window window;
public WindowAdapter(Window window)
{
if (window == null)
{
throw new ArgumentNullException("window");
}
this.window = window;
}
#region IWindow Members
public void Close()
{
this.window.Close();
}
public IWindow CreateChild(object viewModel)
{
var cw = new ContentWindow();
cw.Owner = this.window;
cw.WindowStartupLocation = WindowStartupLocation.CenterOwner;
cw.DataContext = viewModel;
return cw;
}
public void Show()
{
this.window.Show();
}
public bool? ShowDialog()
{
return this.window.ShowDialog();
}
#endregion
}
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
UnityContainer unityContainer = new UnityContainer();
this.Properties["UnityContainer"] = unityContainer;
unityContainer.LoadConfiguration();
unityContainer.Resolve<MainWindow>().Show();
}
public static IUnityContainer UnityContainer
{
get
{
return (IUnityContainer)App.Current.Properties["UnityContainer"];
}
}
启动时受保护的覆盖无效(StartupEventArgs e)
{
基础。启动时(e);
UnityContainer UnityContainer=新的UnityContainer();
this.Properties[“UnityContainer”]=UnityContainer;
unityContainer.LoadConfiguration();
unityContainer.Resolve().Show();
}
公共静态IUnityContainer UnityContainer
{
得到
{
return(IUnityContainer)App.Current.Properties[“UnityContainer”];
}
}
我已经在App.config中注册了我的容器,但这只是我个人的选择
在我的用户控制代码中,我有以下内容:
protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
this.DataContext = App.UnityContainer.Resolve<MyViewModel>();
}
protected override void OnInitialized(事件参数e)
{
基础。初始化(e);
this.DataContext=App.UnityContainer.Resolve();
}
在上面的实例中,MyViewModel未注册,并且没有接口
正如我之前所说,上面的方法对我有效,但是IDE抱怨无法创建用户控件的实例。但是,如果您启动该应用程序,它将工作正常。有两种方法可以做到这一点。下面的代码片段应该可以澄清这一点
//creating Container
IUnityContainer _container = new UnityContainer();
//Data Source
TasksListViewModel _tasksSource = new TasksListViewModel(); //My Data Source
_container.RegisterInstance<TasksListViewModel>(_tasksSource); //Registering it
//Resolve Window
Window1 window = _container.Resolve<Window1>();
//Answer to your question: Inject ViewModel into the View (User control)
//Two ways:
//1. Using Build (assuming View IS already added to the main window with the name "myView")
_container.BuildUp(typeof(TasksListView), window.FindName("myView"));
//---- OR ----
//2. Adding the view to the grid (assuming View IS NOT already added to the main window)
//Resolve View
//TasksListView view = _container.Resolve<TasksListView>();
//Make sure you have grid (content control) named LayoutRoot
//window.LayoutRoot.Children.Add(view); //Add it to the Main Window's grid (LayoutRoot)
window.Show();
//创建容器
IUnityContainer_container=new UnityContainer();
//数据源
TasksListViewModel_tasksSource=new TasksListViewModel()//我的数据源
_容器.RegisterInstance(_tasksSource)//登记
//解析窗口
Window1 window=_container.Resolve();
//回答您的问题:将ViewModel注入视图(用户控件)
//两种方式:
//1. 使用构建(假设视图已添加到名为“myView”的主窗口)
_container.building(typeof(TasksListView),window.FindName(“myView”);
//----或----
//2. 将视图添加到网格(假设视图尚未添加到主窗口)
//解析视图
//TasksListView视图=_container.Resolve();
//确保您有名为LayoutRoot的网格(内容控制)
//window.LayoutRoot.Children.Add(视图)//将其添加到主窗口的网格(LayoutRoot)
window.Show();