【问题标题】:Binding in WPF to element of array specified by property在 WPF 中绑定到由属性指定的数组元素
【发布时间】:2011-05-05 06:45:27
【问题描述】:

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

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

在我后面的代码中,我有这样的东西:

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

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


编辑:

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

【问题讨论】:

    标签: wpf data-binding xaml


    【解决方案1】:

    另一种选择是将 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>
    

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

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

    【讨论】:

    • 感谢 Colin - 这对我的测试应用程序非常有效,并且怀疑它在实际应用中也能正常工作。这是美好的一天——我从你那里学到了一些很酷的东西。 :)
    • 您可能会尝试使用 ConverterParameter 尝试不同的方法来避免多重绑定。不幸的是,这将无济于事,因为 ConverterParameter 不能使用绑定,因为它不是 DependencyProperty,您必须使用 MultiBinding
    【解决方案2】:

    如果您要在 DataContext 上使用 DesertIndex 属性,为什么不使用 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" };
        }
    }
    

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

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

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

    【讨论】:

    • 马克,感谢您的回复。有关更多详细信息,请参阅我对原始问题的编辑。本质上,我正在处理 ListBox 和这些对象 [] 的列表,所以我不知道如何按照您的建议在这种情况下进行取消引用。数据不是我的,我必须照原样处理。想法?
    【解决方案3】:

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

    您还可以使用 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;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2015-08-30
      • 1970-01-01
      • 2011-01-27
      • 2018-05-14
      • 2017-07-20
      • 2020-07-07
      • 1970-01-01
      • 2010-09-30
      • 2011-11-03
      相关资源
      最近更新 更多