3

Hi following suggestion
you have a Textblock which DataContext is:

  • this[0]
  • this[1]
  • this[...]
  • this[n]

this Textblock is a child of a DatagridCell

now i want to get set a Binding based on the Column position

so i wrote Binding RelativeSource={RelativeSource FindAncestor,AncestorType=DataGridCell},Path=Column.DisplayIndex } which works fine

to get a this[...] i need to bind like Binding Path=[0] which also works well

but if i but both together like this:

{ Binding Path=[ {Binding Path=Column.DisplayIndex, RelativeSource={RelativeSource FindAncestor, AncestorType=DataGridCell}} ] }

it doesn't bind here the Error

System.Windows.Data Error: 40 : BindingExpression path error: '[]' property not found on 'object' ''List`1' (HashCode=33153114)'. BindingExpression:Path=[{Binding Path=Column.DisplayIndex, RelativeSource={RelativeSource FindAncestor, AncestorType=DataGridCell} }]; DataItem='List`1' (HashCode=33153114); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')

so does anyone know how to do this?


Edit:

here simple code:

XAML

<DataGrid AutoGenerateColumns="true" Height="200" HorizontalAlignment="Left" Margin="243,12,0,0" Name="grid" VerticalAlignment="Top" Width="200"
          SelectionMode="Extended" SelectionUnit="Cell">
    <DataGrid.Resources>
        <Style TargetType="{x:Type DataGridCell}">
            <Setter Property="Background" Value="Green"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="DataGridCell">
                        <StackPanel >
                            <TextBlock Text="{Binding Path=Column.DisplayIndex, RelativeSource={RelativeSource FindAncestor, AncestorType=DataGridCell} }" />
                            <TextBlock Text="{Binding Path=[0] }" />
                        </StackPanel>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </DataGrid.Resources>
</DataGrid>

CS

/// <summary>
/// Interaktionslogik für MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        var gridList = new List<List<MyCell>>();

        for (int i = 0; i < 5; i++)
        {
            var cell1 = new MyCell { Text1 = "nr " + i, Text2 = "value1" };
            var cell2 = new MyCell { Text1 = "nr " + i, Text2 = "value2" };


            var sublist = new List<MyCell>();
            sublist.Add(cell1);
            sublist.Add(cell2);

            gridList.Add(sublist);
        }

        grid.ItemsSource = gridList;
    }
}

public class MyCell
{
    string value1;
    string value2;

    public string Text1
    {
        get { return value1; }
        set { value1 = value; }
    }
    public string Text2
    {
        get { return value2; }
        set { value2 = value; }
    }
}
WiiMaxx
  • 5,322
  • 8
  • 51
  • 89

1 Answers1

2

Interesting constillation you got there.

It is very well possible to do what you actually asking for.

The Binding Path has a property called PathParameters and here is how you can use it:

new Binding {
    Path = new PropertyPath("Values[(0)]", new DateTime(2011, 01, 01))
}

In this example instead of zero the date is gonna be injected.

You will find here about path syntax:

http://msdn.microsoft.com/en-us/library/ms742451.aspx

Edit 2:

Hack wpf to make it work.

Lets say this is your ViewModel.

public class VM
{
    private Dictionary<int, string> dic;

    public Dictionary<int, string> Dic
    {
        get
        {
            if (dic == null)
            {
                dic = new Dictionary<int, string>();
                dic[123] = "Hello";
            }

            return dic;
        }
    }

    public int Index
    {
        get
        {
            return 123;
        }
    }
}

This is XAML:

I am having DataContext inside Resources as you can see.

<Window x:Class="WpfApplication1.MainWindow"
        xmlns:helper="clr-namespace:WpfApplication1.Helper">
    <Window.Resources>
        <local:VM x:Key="viewModel"/>
    </Window.Resources>

    <StackPanel>
       <Button>
        <Button.Content>
            <helper:ParameterBinding Source="{StaticResource viewModel}" PropertyName="Dic" HasIndex="True">
                <helper:ParameterBinding.ParameterObject>
                    <helper:ParameterBindingHelperObject BindableParameter="{Binding Source={StaticResource viewModel}, Path=Index}"/>
                </helper:ParameterBinding.ParameterObject>
            </helper:ParameterBinding>
        </Button.Content>
      </Button>
    </StackPanel>
</Window>

And this is the key to everything:

public class ParameterBinding : Binding
{
    private ParameterBindingHelperObject parameterObject;

    public ParameterBindingHelperObject ParameterObject
    {
        get
        {
            return parameterObject;
        }

        set
        {
            this.parameterObject = value;
            this.parameterObject.Binding = this;
        }
    }

    public bool HasIndex
    {
        get;
        set;
    }

    public string PropertyName
    {
        get;
        set;
    }

    public void UpdateBindingPath()
    {
        string path = this.PropertyName + (HasIndex ? "[" : "") + this.ParameterObject.BindableParameter + (HasIndex ? "]" : "");
        this.Path = new PropertyPath(path);
    }
}

public class ParameterBindingHelperObject : DependencyObject
{
    private ParameterBinding binding;

    public ParameterBinding Binding
    {
        get
        {
            return binding;
        }

        set
        {
            this.binding = value;
            this.binding.UpdateBindingPath();
        }
    }

    public object BindableParameter
    {
        get { return (object)GetValue(BindableParameterProperty); }
        set { SetValue(BindableParameterProperty, value); }
    }

    public static readonly DependencyProperty BindableParameterProperty =
        DependencyProperty.Register("BindableParameter", typeof(object), typeof(ParameterBindingHelperObject), new UIPropertyMetadata(null, PropertyChangedCallback));

    private static void PropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
    {
        ParameterBindingHelperObject obj = (ParameterBindingHelperObject)dependencyObject;
        if (obj.Binding != null)
        {
            obj.Binding.UpdateBindingPath();
        }
    }
}

I inherit from Binding and place a bindable property which will serve as parameter.

Technically you can change this and make most awesome binding ever. You could allow to change index number at runtime and path will change.

What you think of this?

dev hedgehog
  • 8,698
  • 3
  • 28
  • 55
  • i make it so complicated because it is complicated :D the based problem why i need to do such a hilarious complicated is i want to bind some data (objects) as cells in a `Datagrid` but the `DataContext` of a `DatagridCell` is allway's the RowItem (in my case a `List`) so i need to access the indexer ... – WiiMaxx Oct 29 '13 at 09:47
  • Return index property with proper formatation like I suggested. And it work, wouldnt it? – dev hedgehog Oct 29 '13 at 09:50
  • to your first suggestion i don't understand how this should work and your second one doesn't work if i want to use `new Binding { Path = new PropertyPath("[(0)]",...}` because the first char can't be an `[` :( – WiiMaxx Oct 29 '13 at 09:51
  • i added a example of what i'm currently doing the goal is to get the access to `Text1` and/or `Text2` – WiiMaxx Oct 29 '13 at 09:58
  • I just throw that code in my visual studio. It seems I copy pasted something crappy from the internet. Damn. I edited the question. Yes, PropertyPath can only be set in code and not in XAML – dev hedgehog Oct 29 '13 at 10:05
  • Create a class that derives from Binding itself and inside there offer property that allows to set any object which will serve as pamater and may be added to PathParameters. Its just few lines of code. In XAML you can use your custom parameterized binding. :) So you can avoid code behind. – dev hedgehog Oct 29 '13 at 10:16
  • could you please provide me an simple example? – WiiMaxx Oct 29 '13 at 10:25
  • mhh i tryed your version with `Source="stackPanel1.DataContext"`instead of `Source="{StaticResource viewModel}"` but the generated binding is _{Path=Dic[]}_ so the Index is missing :( – WiiMaxx Oct 29 '13 at 13:09
  • Source cannot be set like this: Source="stackPanel1.DataContext" you are giving a simple string to Source in such case. – dev hedgehog Oct 29 '13 at 13:20
  • what do you mean with simple string ? (_Source=""_) because all things i tryed doesn't work :( – WiiMaxx Oct 29 '13 at 13:28
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/40188/discussion-between-wiimaxx-and-dev-hedgehog) – WiiMaxx Oct 29 '13 at 13:29