在 WPF 中绑定到由属性指定的数组元素

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4100690/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 22:16:20  来源:igfitidea点击:

Binding in WPF to element of array specified by property

wpfdata-bindingxaml

提问by itsmatt

Say I've got some TextBlocks on my UI, something like so:

假设我的 UI 上有一些 TextBlock,如下所示:

<StackPanel Orientation="Vertical">
    <TextBlock Text="{Binding DessertIndex}" />
    <TextBlock Text="{Binding Food[2]}" />
    <TextBlock Text="{Binding Food[{Binding DessertIndex}]}" />
</StackPanel>

and in my code behind I've got something like this:

在我后面的代码中,我有这样的事情:

public partial class MainWindow : Window
{
    public int DessertIndex
    {
        get { return 2; }
    }

    public object[] Food
    {
        get
        {
            return new object[]{"liver", "spam", "cake", "garlic" };
        }
    }

    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;
    }
}

The first two TextBlocks display fine for me, displaying 2 and 'cake' respectively. The third one doesn't accomplish what I'd like, namely use the DessertIndex property to index into that array and also display 'cake'. I did a little searching here on SO for a similar question but didn't find one. Ultimately, I don't want to specify values like 2 in my .xaml file and would like to rely upon a property instead for indexing into that array. Is this possible? If so, what am I doing wrong here?

前两个 TextBlock 对我来说显示良好,分别显示 2 和 'cake'。第三个没有完成我想要的,即使用 DessertIndex 属性索引到该数组并显示“蛋糕”。我在 SO 上做了一些类似的问题的搜索,但没有找到。最终,我不想在我的 .xaml 文件中指定像 2 这样的值,而是想依赖一个属性而不是索引到该数组中。这可能吗?如果是这样,我在这里做错了什么?



EDIT:

编辑:

So what I more closely have is a situation where the data is a List of these object[] and I'm using the above StackPanel as part of a DataTemplate for a ListBox. So the idea, as Mark Heath suggests below, of using a property that dereferences the array doesn't seem to work as I'd want. Ideas?

所以我更接近的是数据是这些对象[]的列表并且我使用上面的StackPanel作为ListBox的DataTemplate的一部分的情况。因此,正如 Mark Heath 在下面所建议的那样,使用取消引用数组的属性的想法似乎并不像我想要的那样工作。想法?

回答by Colin Thomsen

Another alternative is to use MultiBinding with a converter:

另一种选择是将 MultiBinding 与转换器一起使用:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel Orientation="Vertical">
        <StackPanel.Resources>
            <local:FoodIndexConverter x:Key="foodIndexConverter" />
        </StackPanel.Resources>
        <TextBlock Text="{Binding DessertIndex}" />
        <TextBlock Text="{Binding Food[2]}" />
        <TextBlock>
                <TextBlock.Text>
                    <MultiBinding Converter="{StaticResource foodIndexConverter}">
                        <Binding Path="DessertIndex" />
                        <Binding Path="Food"/>
                    </MultiBinding>
                </TextBlock.Text>
        </TextBlock>
    </StackPanel>
</Window>

Then in the code-behind, the converter is defined something like this:

然后在代码隐藏中,转换器定义如下:

namespace WpfApplication1
{
    public class FoodIndexConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (values == null || values.Length != 2)
                return null;

            int? idx = values[0] as int?;
            object[] food = values[1] as object[];

            if (!idx.HasValue || food == null)
                return null;

            return food[idx.Value];
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

回答by Mark Heath

if you are going to the trouble of having a DesertIndexproperty on your DataContext, why not a property that dereferences the Food array with DesertIndex:

如果您要DesertIndex在 DataContext 上设置一个属性,那么为什么不用一个使用 DesertIndex 取消引用 Food 数组的属性:

public object SelectedFood
{
    get { return Food[DessertIndex]; }
}    

public int DessertIndex
{
    get { return 2; }
}

public object[] Food
{
    get
    {
        return new object[]{"liver", "spam", "cake", "garlic" };
    }
}

then you can bind directly to that:

那么你可以直接绑定到那个:

<TextBlock Text="{Binding SelectedFood}" />

This is essentially the "MVVM" approach: make the datacontext object have properties that are just right for binding to.

这本质上是“MVVM”方法:使数据上下文对象具有适合绑定的属性。

回答by Nina Kaprez

Just To add on the great answer by Colin Thomsen.

只是为了补充 Colin Thomsen 的精彩回答。

You could also use C# dynamickeyword to make this solution work with pretty much every container type. Or even bind to multidimensional containers "{Binding Food[{Binding DessertIndex1}][{Binding DessertIndex2}]}"

您还可以使用 C#dynamic关键字使此解决方案适用于几乎所有容器类型。甚至绑定到多维容器“{Binding Food[{Binding DessertIndex1}][{Binding DessertIndex2}]}”

public class ContainerDoubleAccessConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        try
        {
            dynamic idx1 = values[0];
            dynamic idx2 = values[1];
            dynamic container = values[2];

            return container[idx1][idx2];
        }
        catch (System.Exception err)
        {
            DebugTrace.Trace("bad conversion " + err.Message);
        }
        return null;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        return null;
    }
}