Bind a Property that is outside of an Itemscontrol in XAML
Asked Answered
C

2

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!" />
Cassell answered 18/6, 2015 at 13:41 Comment(1)
Can you check my example on how to define your properties? It might be helpful.Hyperventilation
D
16

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}}}" />
Dioptric answered 18/6, 2015 at 13:42 Comment(6)
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 :(Cassell
it seems that I still get the same problem. I am using caliburns MVVM. (sorry, forgot to mention that too)Cassell
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?Overhand
Seems it works now. I had to double check my code. Datacontext.Propertyname with UserControl solved my problemCassell
@Overhand Please note that AncestorType=ItemsControl is also valid XAML. Your edit doesn't contribute much to this post.Demagogic
@Demagogic 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.Overhand
H
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

Hyperventilation answered 18/6, 2015 at 14:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.