如何在绑定中使用包含绑定的绑定

3

您好,以下是建议:
您有一个TextBlock其DataContext为:

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

此TextBlock是DatagridCell的子级。

现在我想基于列位置设置绑定。

所以我写了Binding RelativeSource={RelativeSource FindAncestor,AncestorType=DataGridCell},Path=Column.DisplayIndex},这很好用。

要像Binding Path=[0]那样获得this[...],也可以正常工作。

但如果我把它们结合起来:

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

它没有在这里绑定错误。

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')

请问有人知道如何做到这一点吗?


编辑:

以下是简单的代码:

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; }
    }
}

“this”是什么?是你的UserControl吗?我猜你有一个索引器属性可以使用,而不仅仅是[ ]吧? - Millie Smith
this[] 是我的 DataContext 和一个 List<MyCell> 的一部分。 - WiiMaxx
2
我认为没有比这里的解决方案更简单的方法了。这只是几行代码而已。不妨试试... - Millie Smith
谢谢提供链接,我没有注意到已经有一个类似的问题了。 - WiiMaxx
1个回答

2

你的星座很有趣。

实际上,你所要求的是完全可能做到的。

Binding Path 有一个叫做 PathParameters 的属性,以下是如何使用它:

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

在这个例子中,日期将被注入而不是零。
您可以在此处了解路径语法: http://msdn.microsoft.com/en-us/library/ms742451.aspx 编辑2:
黑客WPF,使其正常工作。
假设这是您的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;
        }
    }
}

这是XAML:

你可以看到我在资源中有DataContext。

<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>

这就是一切的关键:

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();
        }
    }
}

我继承自Binding并放置一个可绑定的属性作为参数。

从技术上讲,您可以更改此内容并创建最棒的绑定。您可以允许在运行时更改索引号,路径会发生变化。

您对此有什么想法?


我把它搞得这么复杂是因为它本身就很复杂:D。基本问题是我需要将一些数据(对象)绑定为Datagrid中的单元格,但是DatagridCellDataContext始终是行项(在我的情况下是List<MyCell>),所以我需要访问索引器... - WiiMaxx
按照我建议的格式返回索引属性。这样做应该可以正常工作,不是吗? - dev hedgehog
对于您的第一个建议,我不理解这应该如何工作;对于第二个建议,如果我想使用 new Binding { Path = new PropertyPath("[(0)]",...},它将不起作用,因为第一个字符不能是 [ :( - WiiMaxx
我只是把那段代码扔进了我的Visual Studio。看起来我从互联网上复制粘贴了一些垃圾代码。该死。我编辑了问题。是的,PropertyPath只能在代码中设置,而不能在XAML中设置。 - dev hedgehog
无法像这样设置源:Source="stackPanel1.DataContext"在这种情况下,您正在简单地将一个字符串提供给Source。 - dev hedgehog
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接