tags:

views:

716

answers:

2

Hi,

I've got an expander with a couple of TextBlocks in the top bar which i'm using to give a title and a piece of key information.

Ideally i want to set the path to key piece of information, but i can't work out how to bind the path of the binding to another path (i apologise if i'm not making much sense!)

In the following xaml the first bit works, the second bit is what i'm struggling with.

<TextBlock Text="{Binding Path=Header.Title}"/>

<TextBlock Text="{Binding Path={Binding Path=Header.KeyValuePath}}"/>

KeyValuePath might contain something like "Vehicle.Registration" or "Supplier.Name" depending on the Model.

Can anyone point me in the right direction please? Any help gratefully received!

+3  A: 

I don't think it can be done in pure XAML... Path is not a DependencyProperty (and anyway Binding is not a DependencyObject), so it can't be the target of a binding

You could modify the binding in code-behind instead

Thomas Levesque
A: 

I haven't found a way to do this in XAML but I did this in code behind. Here is the approach I took.

Firstly, I wanted to do this for all items in an ItemsControl. So I had XAML like this:

<ListBox x:Name="_events" ItemsSource="{Binding Path=Events}">
    <ListBox.ItemTemplate>
        <DataTemplate DataType="{x:Type Events:EventViewModel}">
            <TextBlock Name="ActualText" />
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Then, in code behind construction I subscribe to the ItemContainerGenerator:

InitializeComponent();
_events.ItemContainerGenerator.StatusChanged
     += OnItemContainerGeneratorStatusChanged;

This method looks like:

private void OnItemContainerGeneratorStatusChanged(object sender, EventArgs e)
{
  if (_events.ItemContainerGenerator.Status!=GeneratorStatus.ContainersGenerated)
    return;

  for (int i = 0; i < _viewModel.Events.Count; i++)
  {
    // Get the container that wraps the item from ItemsSource
    var item = (ListBoxItem)_events.ItemContainerGenerator.ContainerFromIndex(i);
    // May be null if filtered
    if (item == null)
      continue;
    // Find the target
    var textBlock = item.FindByName("ActualText");
    // Find the data item to which the data template was applied
    var eventViewModel = (EventViewModel)textBlock.DataContext;
    // This is the path I want to bind to
    var path = eventViewModel.BindingPath;
    // Create a binding
    var binding = new Binding(path) { Source = eventViewModel };
    textBlock.SetBinding(TextBlock.TextProperty, binding);
  }
}

If you only have a single item to set the binding upon, then the code would be quite a bit simpler.

<TextBlock x:Name="_text" Name="ActualText" />

And in code behind:

var binding = new Binding(path) { Source = bindingSourceObject };
_text.SetBinding(TextBlock.TextProperty, binding);

Hope that helps someone.

Drew Noakes