在 Silverlight/WPF 中绑定复杂属性

Posted

技术标签:

【中文标题】在 Silverlight/WPF 中绑定复杂属性【英文标题】:Binding complex properties in Silverlight/WPF 【发布时间】:2010-10-16 19:25:33 【问题描述】:

假设我有一个看起来像这样的自定义数据类型:

public class MyDataType

  public string SimpleProp1;
  public string SimpleProp2;
  public List<SomeType> ComplexProp;

现在我有一个动态创建的数据绑定控件(即 ItemsControl 或 DataGrid)。 xaml 代码中定义的绑定如何访问复杂属性的子属性?我认为它应该看起来像这样:

<TextBox Text="Binding simpleSubProp, path=ComplexProp[0]" />

<TextBox Text="Binding path=ComplexProp[0].simpleSubProp" />

但是这两个都给了我 xml 解析错误。它应该如何正确显示?甚至可以以这种方式引用集合属性的特定项目吗?如果不是,我还有什么其他选择?

编辑,场景似乎不够清晰:

我有一个

IEnumberable<MyDataType>

绑定到 ItemsControl,在 DataTemplate 内我有多个 TextBox,需要引用复杂属性列表中对象的子属性。

【问题讨论】:

【参考方案1】:

我不确定你能做到这一点。通常,您会将列表绑定到列表框(或另一个“重复”控件)之类的东西上,然后其中的每个项目都将能够绑定到列表中的相关元素。

【讨论】:

我可能还不够清楚,我有一个绑定到 ItemsControl 的 IEnumerable。在我的 ItemsControl 的 DataTemplate 中,我需要引用复杂属性中特定项目的子属性。【参考方案2】:

试试 Binding ComplexProp(0).simpleSubProp。如果这不起作用,您也可以编写一个简单的转换器来执行此操作。

【讨论】:

感谢您的回答,不幸的是,这给了我一个 System.ArgumentException“无效的绑定路径;字符”。这个转换器的外观如何?我认为转换器通常用于以特定方式格式化数据【参考方案3】:

根据Path Syntax on MSDN,你可以这样做:

<TextBox Text="Binding ComplexProp[0].simpleSubProp" />

可能是小写的“path=”给了你错误?试试“路径=”。另外,不确定这是否适用于 Silverlight...

【讨论】:

该页面用于 WPF,而不是 Silverlight。 Silverlight 不支持绑定中的索引属性。 问题的标题是“Silverlight/WPF”。 索引方法似乎只适用于 Silverlight 中的某些情况,不过谢谢! Silverlight 3 支持绑定中的索引属性。【参考方案4】:

Silverlight Indexers in property paths are broken 中的 poperty 路径索引器似乎已损坏。绕过它的方法是在帖子中建议并使用 IValueConverter。

XAML

<UserControl x:Class="Silverlight.Mine.Page"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
  xmlns:sys="System"
  xmlns:sm="clr-namespace:Silverlight.Mine;assembly=Silverlight.Mine"
  Width="400" Height="300">
    <UserControl.Resources> 
       <sm:SomeTypeConverter x:Key="MySomeTypeConverter" />
    </UserControl.Resources>    
    <Grid x:Name="LayoutRoot" Background="White">
        <TextBlock x:Name="myTextBlock" Text="Binding Path=SomeDates, Converter=StaticResource MySomeTypeConverter" />
    </Grid>
</UserControl>

C# Page.xaml.cs

namespace Silverlight.Mine

    public partial class Page : UserControl
    
        private SomeType m_mySomeType = new SomeType();

        public Page()
        
            InitializeComponent();
            myTextBlock.DataContext = m_mySomeType;
        
    

C# SomeType.cs

namespace Silverlight.Mine

    public class SomeType
    
        public List<DateTime> SomeDates  get; set; 

        public SomeType()
        
            SomeDates = new List<DateTime>();
            SomeDates.Add(DateTime.Now.AddDays(-1));
            SomeDates.Add(DateTime.Now);
            SomeDates.Add(DateTime.Now.AddDays(1));
        
    

    public class SomeTypeConverter : IValueConverter
    
        public object Convert(object value,
                       Type targetType,
                       object parameter,
                       CultureInfo culture)
        
            if (value != null)
            
                List<DateTime> myList = (List<DateTime>)value;
                return myList[0].ToString("dd MMM yyyy");
            
            else
            
                 return String.Empty;
            
        

        public object ConvertBack(object value,
                              Type targetType,
                              object parameter,
                              CultureInfo culture)
        
            if (value != null)
            
                return (List<DateTime>)value;
            
            return null;
        
    

【讨论】:

【参考方案5】:

我一直都在做这种事情,有两种方法可以解决这个问题,具体取决于你想从中得到什么。

如果您真的只想要列表中的一个特定成员,您可以使用转换器。 XAML 看起来像这样:

<TextBox Text="Binding MyDataTypeInstance, Converter=StatacResources SpecificInstanceConverter" />

不过,这通常不是我需要的,通常我需要一个控件来显示整个复杂对象,如果是这种情况,方法更像如下:

<StackPanel>
     <Textblock Text="Binding SimpleProp1"/>
     <TextBlock Text="Bidning SimpleProp2"/>
     <ItemsControl ItemsSource="Binding ComplexProp>
          <ItemsControl.ItemsTemplate>
               <DataTemplate>
                    <StackPanel>
                         <TextBlock Text="Binding ComplexPropertyName/>
                         <InputToolkit:NumericUpDown Value="Binding ComplexPropertyValue/>
                    </StackPanel>
               </DataTemplate>
          </ItemsControl.ItemsTemplate>
     </ItemsControl>
</StackPanel>

我喜欢这种方法,因为我的 GUI 与我的业务对象匹配,因此它通常比我在代码隐藏中检查特定索引时干净得多。

【讨论】:

【参考方案6】:

为了概括这一点,我建议你使用其他人提到的值转换器,并使用 ConverterParam 选项来传递索引。

【讨论】:

【参考方案7】:

这在 Silverlight 4 中现在可以正常工作了。

需要注意的是,该类有三个公共字段。将它们更改为属性(并且也是实现 INotifyPropertyChanged 的​​一个想法),然后下面的代码就可以工作了。

<StackPanel>
    <TextBlock Text="Binding Path=SimpleProp1" />
    <TextBox Text="Binding Path=ComplexProp[0].SimpleSubProp, Mode=TwoWay" Width="200" Height="60"/>
</StackPanel>

大小写也很重要,因为绑定区分大小写。

【讨论】:

以上是关于在 Silverlight/WPF 中绑定复杂属性的主要内容,如果未能解决你的问题,请参考以下文章

什么音频格式适用于 Silverlight + WPF?

Silverlight/WPF 用十六进制颜色设置椭圆

.NET 开发的未来:ASP.NET 还是 WPF/Silverlight/Winforms? [关闭]

如何根据复杂用户的选择显示绑定的 NSManagedObject 的属性?

Winforms DataGridView 数据绑定到复杂类型/嵌套属性

如果参数名称等于属性名称,则来自查询的 ASP.NET Core Web API 复杂类型绑定不起作用