简体   繁体   English

WPF / C#从父视图向自定义控件分配ViewModel

[英]WPF/C# Assigning a ViewModel to a custom control from parent view

I'm very new to C# and WPF, and I'm struggling a bit to get data where I need it. 我是C#和WPF的新手,我在为在需要的地方获取数据而苦苦挣扎。

I have one master set of data, which needs to be shared with various user controls, each of which have their own ViewModel. 我有一套主数据,需要与各种用户控件共享,每个用户控件都有自己的ViewModel。 The problem is that I don't seem to be able to assign a ViewModel to a control from the parent XAML and then access that ViewModel from within the custom control's XAML. 问题是我似乎无法从父XAML向控件分配ViewModel,然后再从自定义控件的XAML中访问该ViewModel。

I bind the control to a Viewmodel, but then the datacontext within the control doesn't allow me to access that model within the xaml, or I can set the datacontext in the user control so I can access its viewmodel, but then I can't bind to the viewmodel in xaml (because the binding is looking in the local datacontext, not the parent). 我将控件绑定到Viewmodel,但是控件中的datacontext不允许我在xaml中访问该模型,或者可以在用户控件中设置datacontext,以便可以访问其viewmodel,但是我可以t绑定到xaml中的视图模型(因为绑定正在本地数据上下文中查找,而不是在父级中查找)。

I may be going about this all wrong, most examples I've seen seem to instantiate a ViewModel in the custom control xaml, but then I don't see how you get that ViewModel to reference the correct DataModel (or specific part of the datamodel). 我可能会犯错,我看到的大多数示例似乎都在自定义控件xaml中实例化了一个ViewModel,但是然后我看不到如何获得该ViewModel来引用正确的DataModel(或数据模型的特定部分) )。

The following hopefully explains what I am trying to do. 以下内容有望说明我正在尝试做的事情。

Firstly I have my data model, in DataModel.cs 首先,我在DataModel.cs中有我的数据模型

using System;
using System.Collections.Generic;

namespace BindingTest1
{

    public class DataModel
    {
        private List<string>[] _dataLists;
        public List<string>[] DataLists
        {
            get { return _dataLists; }
        }


        public DataModel()
        {

            List<string> list0 = new List<string> { "One", "Two", "Three" };
            List<string> list1 = new List<string> { "Alpha", "Beta", "Gamma" };
            _dataLists = new List<String>[] { list0, list1 };
        }
    }
}

In MainViewModel.cs 在MainViewModel.cs中

namespace BindingTest1
{
    class MainViewModel
    {
        private MyViewModel _myFirstViewModel;
        public MyViewModel MyFirstViewModel
        {
            get { return _myFirstViewModel; }
        }

        private MyViewModel _mySecondViewModel;
        public MyViewModel MySecondModel
        {
            get { return _mySecondViewModel; }
        }

        private DataModel _dataModel;
        public DataModel DataModel
        {
            get { return _dataModel; }
        }

        public MainViewModel()
        {
            _dataModel = new DataModel();
            _myFirstViewModel = new MyViewModel(_dataModel.DataLists[0]);
            _mySecondViewModel = new MyViewModel(_dataModel.DataLists[0]);
        }
    }
}

MainWindow.xaml MainWindow.xaml

<Window x:Class="BindingTest1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:BindingTest1"
        mc:Ignorable="d"
        xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
        Title="MainWindow" Height="350" Width="525">

    <Window.DataContext>
        <local:MainViewModel/>
    </Window.DataContext>

    <Grid>

        <StackPanel HorizontalAlignment="Stretch" Height="100"  VerticalAlignment="Top" Orientation="Horizontal">

        <!-- These were just to check the data was being set up properly -->    
        <ListBox x:Name="listBox1" HorizontalAlignment="Left" Height="100"  VerticalAlignment="Top" Width="100" ItemsSource="{Binding DataModel.DataLists[0]}"/>
        <ListBox x:Name="listBox2" HorizontalAlignment="Left" Height="100"  VerticalAlignment="Top" Width="100" ItemsSource="{Binding DataModel.DataLists[1]}"/>

        <!-- this is what I want to be able to do -->
        <local:MyView ViewModel="{Binding MyFirstViewModel}"/>
        <local:MyView ViewModel="{Binding MySecondViewModel}"/>

        </StackPanel>

    </Grid>
</Window>

(Codebehind is default) (默认为Codebehind)

In MyViewModel.cs 在MyViewModel.cs中

using System;
using System.Collections.Generic;

namespace BindingTest1
{
    public class MyViewModel
    {
        private List<string> _dataList;
        public List<string> DataList
        {
            get { return _dataList; }
        }

        public MyViewModel(List<string> list)
        {
            _dataList = new List<String>(list);
            _dataList.Add("Some Local Processing");
        }
    }
}

MyView.xaml MyView.xaml

<UserControl x:Class="BindingTest1.MyView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:BindingTest1"
             mc:Ignorable="d" 
             d:DesignHeight="100" d:DesignWidth="100">
    <Grid>
        <ListBox x:Name="listBox" HorizontalAlignment="Left" Height="100" VerticalAlignment="Top" Width="100" ItemsSource="{Binding ViewModel.DataList}"/>
    </Grid>
</UserControl>

Codebehind 代码隐藏

using System.Windows;
using System.Windows.Controls;

namespace BindingTest1
{
    /// <summary>
    /// Interaction logic for MyView.xaml
    /// </summary>
    public partial class MyView : UserControl
    {
        public MyViewModel ViewModel
        {
            get { return (MyViewModel)GetValue(ViewModelProperty); }
            set { SetValue(ViewModelProperty, value); }
        }

        public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register("ViewModel", typeof(MyViewModel), typeof(MyView), 
            new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.None, new PropertyChangedCallback(OnViewModelChanged)));

        public MyView()
        {
            InitializeComponent();
        }

        private static void OnViewModelChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            // Just making sure the right thing is being received
            List<string> dataList = (e.NewValue as MyViewModel).DataList;
            foreach(string line in dataList)
            {
                System.Console.WriteLine(line);
            }
        }
    }
}

Here's how you ought to do this. 这是您应该执行的操作。 Your view doesn't need a ViewModel property. 您的视图不需要ViewModel属性。 It should bind to properties of its DataContext, which will be the viewmodel. 它应该绑定到其DataContext的属性,即ViewModel。

view: 视图:

ItemsSource="{Binding DataList}"

Window: 窗口:

<Window.Resources>
    <DataTemplate DataType="{x:Type local:MyViewModel}">
        <local:MyView 
            />
    </DataTemplate>
</Window.Resources>

<Grid>

    <StackPanel HorizontalAlignment="Stretch" Height="100"  VerticalAlignment="Top" Orientation="Horizontal">

        <!-- ... -->

        <ContentControl Content="{Binding MyFirstViewModel}"/>
        <ContentControl Content="{Binding MySecondViewModel}"/>
    </StackPanel>

I don't think you need a dependency property here. 我认为这里不需要依赖项属性。

Try this. 尝试这个。

<local:MyView DataContext="{Binding MyFirstViewModel}"/>
<local:MyView DataContext="{Binding MySecondViewModel}"/>

and bind the DataList to ItemsSource in the MyView XAML. 并将DataList绑定到MyView XAML中的ItemsSource。

As you assigned MyFirstViewModel to the DataContext of MyView, bindings inside will look in MyFirstViewModel for the ItemsSource. 当您将MyFirstViewModel分配给MyView的DataContext时,内部绑定将在MyFirstViewModel中查找ItemsSource。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM