Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
统一及;WPF-通过属性注入将DataContext注入子控件_Wpf_Dependency Injection_Unity Container - Fatal编程技术网

统一及;WPF-通过属性注入将DataContext注入子控件

统一及;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;} }

我遵循Jason Dollinger的MVVM示例,从中学习将Unity与MVVM WPF应用程序结合使用的基础知识。我按照他的基本架构构建了一个简单的示例,使用属性注入和依赖属性将viewmodels注入到视图中。我的示例有一个主窗口,在该窗口的XAML中创建了一个子用户控件。子控件(以及主窗口)具有用于指定viewmodel的属性:

[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();