Search code examples
c#xamltemplatesdata-bindingitemscontrol

How to access a property path of each object in ItemsSource of a ListView from a DataTemplate


How can I access a property path of each object in ItemsSource of a ListView from a DataTemplate? I'm trying something like

public class Person : INotifyPropertyChanged
{
    private string _name;
    public string Name
    {
        get {return _name;}
        set
        {
            _name = value;
            OnPropertyChanged();
        }
    }
}

public partial class MyControl : UserControl, INotifyPropertyChanged
{
    private ObservableCollection<Person> _persons;
    public ObservableCollection<Person> Persons
    {
        get {return _persons;}
        set
        {
            _persons = value;
            OnPropertyChanged();
        }
    }
}

<!-- MyControl.xaml.cs -->
<Grid DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}">
    <ListView ItemsSource="{Binding Persons}">
        <ListView.View>
            <GridView>
                <GridViewColumn Header="Name1" DisplayMemberBinding="{Binding Name}"/>
                <GridViewColumn Header="Name2">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <TextBlock DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataContext}"
                                    Text="{Binding Name}" TextAlignMent="Center"/>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
            </GridView>
        </ListView.View>
    </ListView>
</Grid>

In MyControl.xaml.cs, When I use DisplayMemberBinding in a GridViewColumn of a ListView, the Name Property of each Person object in the ItemsSource Persons can be directly bound as in Name1. But when I set a DataTemplate to a GridViewColumn in order, for example, to manually set TextAlignMent as in Name2, it is impossible to directly access the Name Property of each Person object in the ItemsSource Persons.

I resolved this problem by using TemplatedParent as shown in the code above. Although this code normally works and I can get what I'm aiming to, the VisualStudio warns me with the message "Can't resolve the symbol" in the part of Text="{Binding Name}". Is there a simpler and more appropriate way to realize this kind of DataBinding?


Solution

  • You just bind to the Name property

    <GridViewColumn.CellTemplate>
         <DataTemplate>
            <TextBlock Text="{Binding Name}" TextAlignment="Center"/>
         </DataTemplate>
    </GridViewColumn.CellTemplate>
    

    And you don't need to do this:

     <Grid DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}">
    

    The DataContext is accesible to the entire tree.

    If you're not using MVVM you can set the datacontext in code behind:

     public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this;
            ...
    

    If you get this to work, errors and warnings in Output Window are just false positives