在ItemsControl中使用View as DataTemplate时未设置DataContext

时间:2016-05-26 06:29:14

标签: c# wpf mvvm datacontext itemscontrol

我有一个ViewModel的ObservableCollection,我想绑定到包含相关子视图的ItemsControl。当我将ViewModels添加到我的集合中时,ItemsControl中会生成适当数量的子视图。但是,每个生成的视图的DataContext都为null。如果我内联我的子视图,它可以正常工作。那么,我需要做什么才能将我的子视图的DataContext设置为我的ViewModels?

这是我的父ViewModel中的相关位:

    public ObservableCollection<ChildViewModel> Numbers { get; set; }

    public ParentViewModel()
    {
        Numbers = new ObservableCollection<ChildViewModel>();
    }

    private void ShowNumbers()
    {
        foreach (var num in Enumerable.Range(0, number))
        {
            var childView = new ChildViewModel(number.ToString());
            Numbers.Add(childView);
        }
    }

父视图中的相关位:

        <ItemsControl ItemsSource="{Binding Numbers, UpdateSourceTrigger=PropertyChanged}">
            <ItemsControl.ItemTemplate>
                <DataTemplate DataType="{x:Type vm:ChildViewModel}">
                    <v:ChildView />
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>

儿童观点:

<UserControl x:Class="TestWpfApp.Views.ChildView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:prism="http://prismlibrary.com/"             
         prism:ViewModelLocator.AutoWireViewModel="True">
<Grid>
    <Label Content="{Binding NumberString}" Width="30" Height="30" BorderThickness="1" BorderBrush="Black" HorizontalAlignment="Center"/>
</Grid>
</UserControl>

Child ViewModel:

public class ChildViewModel : BindableBase
{
    private string numberString;
    public string NumberString
    {
        get
        {
            return numberString;
        }
        set
        {
            SetProperty(ref numberString, value);
        }
    }

    public ChildViewModel() { }

    public ChildViewModel(string number)
    {
        NumberString = number;
    }
}

显然,我有一些错误的配置,但我不能为我的生活找出什么。

仅供参考我正在使用棱镜库

2 个答案:

答案 0 :(得分:2)

WPF会自动将DataContext中的项容器元素的ItemsControl设置为相应的项目实例,以便它可以继承到ItemTemplate。显然,当您设置prism:ViewModelLocator.AutoWireViewModel属性时,此机制将被禁用。

所以,只需将它从您的ChildView的XAML中删除:

<UserControl x:Class="TestWpfApp.Views.ChildView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:prism="http://prismlibrary.com/">
    <Grid>
        <Label Content="{Binding NumberString}" Width="30" Height="30"
               BorderThickness="1" BorderBrush="Black" HorizontalAlignment="Center" />
    </Grid>
</UserControl>

作为一般规则,UserControl永远不应该直接或通过像DataContext之类的机制显式设置自己的AutoWireViewModel,因为这有效地阻止了从其父控件继承DataContext

答案 1 :(得分:1)

在ItemsControl中生成适当数量的子视图。
因此可以得出结论,DataContext已正确设置为viewModel,但未应用DataTemplate's

我有同样的问题,我也在使用Prism库。我想分享一下如何做到这一点的方式。也许对你有帮助。我用CompositeCollection

<强>视图模型:

public class MainWindowVM:ViewModelBase
{
    public MainWindowVM()
    {
        LoadData();
    }
    private void LoadData()
    {            
        ObservableCollection<Human> coll = new ObservableCollection<Human>();
        for (int indexLoop = 0; indexLoop < 5; indexLoop++)
        {
            if (indexLoop % 2 == 0)
            {
                coll.Add(new Sportsman() {FirstName=indexLoop.ToString(), LastName=indexLoop.ToString()});
            }
            else
            {
                coll.Add(new Employee() { FirstName = indexLoop.ToString(), LastName = indexLoop.ToString()});
            }                
        }
        CompositeCollection compositeColl = new CompositeCollection();
        compositeColl.Add(new CollectionContainer() { Collection = coll });
        FooData = compositeColl;
    }

    private CompositeCollection fooData;

    public CompositeCollection FooData
    {
        get { return fooData; }
        set
        {
            fooData = value;
        }
    }

}

<强>型号:

public class Human
{        
    private string firstName;
    public string FirstName
    {
        get { return firstName; }
        set { firstName = value; }
    }

    private string lastName;
    public string LastName
    {
        get { return lastName; }
        set { lastName = value; }
    }
}

public class Sportsman:Human
{    }

public class Employee:Human
{    }

查看:

<Window x:Class="ItemsControlWithDataTemplates.MainWindow"
    <!--The code is omitted for the brevity-->
    Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <vm:MainWindowVM/>
    </Window.DataContext>
    <Grid>
        <ItemsControl ItemsSource="{Binding FooData}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <VirtualizingStackPanel/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.Resources>
                <DataTemplate DataType="{x:Type model:Employee}">
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding FirstName}"/>
                        <TextBlock Text=" ( Employee"/>
                        <TextBlock Text="{Binding LastName}"/>
                        <TextBlock Text=")"/>
                    </StackPanel>
                </DataTemplate>
                <DataTemplate DataType="{x:Type model:Sportsman}">
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding FirstName}"/>
                        <TextBlock Text=" - Sportsman "/>
                        <TextBlock Text="{Binding LastName}"/>
                    </StackPanel>
                </DataTemplate>
                <DataTemplate DataType="{x:Type model:Human}">
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding FirstName}"/>
                        <TextBlock Text=" - "/>
                        <TextBlock Text="{Binding LastName}"/>
                    </StackPanel>
                </DataTemplate>
            </ItemsControl.Resources>
        </ItemsControl>    
    </Grid>
</Window>

实际上我在DataContext应用程序中以下列方式设置了Prism

public MyUserControl(IMyViewModel viewModel)
{
    InitializeComponent();
    DataContext = viewModel;
}