13

I am trying to bind a Property that is outside of an Itemscontrol. However that doesn't seem to work.

It seems that in ItemsControl, DataTemplate it refers to what is inside of the collection and not outside of it. I have tried with RelativeResource and Referred to AncestorType for the ViewModel.

Code (VM):

public class Test {
  public string GetThis {get{return "123";} set{}}
  public List<string> IterateProperty {get; set;}
}

XAML (View):

<ItemsControl ItemsSource="{Binding Path=IterateProperty}">
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <TextBlock Text="I want to bind the string property GetThis!" />
Khiem-Kim Ho Xuan
  • 1,301
  • 1
  • 22
  • 45

2 Answers2

15

You need to bind to the DataContext of the parent ItemsControl.

<ItemsControl ItemsSource="{Binding Path=IterateProperty}">
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <TextBlock Text="{Binding DataContext.GetThis,
                                RelativeSource={RelativeSource Mode=FindAncestor,
                                                               AncestorType={x:Type ItemsControl}}}" />
almulo
  • 4,918
  • 1
  • 20
  • 29
Mike Eason
  • 9,525
  • 2
  • 38
  • 63
  • hmm good pinpoint, but I get an error still. But it says now : Cannot resolve property '...' in data context of type 'System.Windows.Controls.ItemsControl' nooooo :( – Khiem-Kim Ho Xuan Jun 18 '15 at 13:52
  • it seems that I still get the same problem. I am using caliburns MVVM. (sorry, forgot to mention that too) – Khiem-Kim Ho Xuan Jun 18 '15 at 14:01
  • If both `GetThis` and `IterateProperty` are really in the same class and public... Then Mike's code should definitely work. @Khiem-KimHoXuan you sure you're not forgetting some important piece of code? – almulo Jun 18 '15 at 14:31
  • Seems it works now. I had to double check my code. Datacontext.Propertyname with UserControl solved my problem – Khiem-Kim Ho Xuan Jun 18 '15 at 15:21
  • @almulo Please note that `AncestorType=ItemsControl` is also valid XAML. Your edit doesn't contribute much to this post. – Clemens Jun 18 '15 at 16:59
  • 3
    @Clemens Oh, well, that wasn't the important part of the edit... I edited just to add context to the code. It might be a small addition, but somebody struggling with RelativeSource Bindings should see it more clearly this way. – almulo Jun 18 '15 at 17:27
5

I've made a fast and full example on this :

<Window x:Class="ParentDataContext.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <DataGrid ItemsSource="{Binding items}" AutoGenerateColumns="False">
        <DataGrid.Columns>
            <DataGridTemplateColumn>
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <CheckBox IsChecked="{Binding IsChecked}"></CheckBox>
                            <TextBlock Margin="5" 
                                       Text="{Binding Path=DataContext.TextFromParent,RelativeSource={RelativeSource AncestorType={x:Type Window}}}"/>
                        </StackPanel>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
        </DataGrid.Columns>
    </DataGrid>
</Grid>

The context for each row is set to each object from the bound list. In our case, to each Model instance from the items collection.

To go back to the parent's DataContext this syntax is used:

Text="{Binding Path=DataContext.TextFromParent,RelativeSource={RelativeSource AncestorType={x:Type Window}}}"/>

Here is the codebehind:

public partial class MainWindow : Window
{
    public string TextFromParent
    {
        get { return (string)GetValue(TextFromParentProperty); }
        set { SetValue(TextFromParentProperty, value); }
    }

    // Using a DependencyProperty as the backing store for TextFromParent.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty TextFromParentProperty =
        DependencyProperty.Register("TextFromParent", typeof(string), typeof(MainWindow), new PropertyMetadata(string.Empty));


    public ObservableCollection<Model> items { get; set; }
    public MainWindow()
    {
        InitializeComponent();
        items = new ObservableCollection<Model>();
        items.Add(new Model() { IsChecked = true });
        items.Add(new Model() { IsChecked = false });
        items.Add(new Model() { IsChecked = true });
        items.Add(new Model() { IsChecked = false });
        TextFromParent = "test";
        this.DataContext = this;
    }
}

You can define your dependency property in your ViewModel.

And here is my simple Model:

public class Model : INotifyPropertyChanged
{
    private bool _IsChecked;

    public bool IsChecked
    {
        get { return _IsChecked; }
        set
        {
            _IsChecked = value;
            PropertyChanged(this, new PropertyChangedEventArgs("IsChecked"));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged = delegate { };
}

As a result, you can access the property defined on your parent's DataContext.

enter image description here

Olaru Mircea
  • 2,570
  • 26
  • 49