سؤال

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; }
    }
}
هل كانت مفيدة؟

المحلول

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?

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top