Связывание сложных свойств в Silverlight / WPF - PullRequest
9 голосов
/ 01 апреля 2009

Допустим, у меня есть пользовательский тип данных, который выглядит примерно так:

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. Как это должно выглядеть правильно? Можно ли как-то ссылаться на конкретный элемент свойства коллекции в souch? Если это не так, какие еще варианты у меня есть?

РЕДАКТИРОВАТЬ, сценарий, кажется, не достаточно ясен:

У меня есть

IEnumberable<MyDataType>

, который связан с ItemsControl, внутри DataTemplate У меня есть несколько TextBox, которые должны ссылаться на свойства объекта в списке сложного свойства.

Ответы [ 7 ]

7 голосов
/ 01 апреля 2009

Похоже, что индексаторы пути poperty не работают в Silverlight Индексаторы в путях свойств не работают . Способ обойти это, как предложено в посте, и использовать 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;
        }
    }
}
4 голосов
/ 25 ноября 2009

Я все время так делаю, есть два способа решить эту проблему в зависимости от того, что вы хотите от нее.

Если вам действительно нужен только один конкретный член списка, вы можете использовать конвертер. 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 совпадает с моими бизнес-объектами, и в результате он обычно оказывается намного чище, чем если бы я проверял определенные индексы в коде позади.

2 голосов
/ 03 июля 2011

Теперь это работает нормально в Silverlight 4.

Следует отметить, что у класса есть три открытых поля. Измените их на Свойства (и было бы также неплохо реализовать INotifyPropertyChanged), и тогда работает следующий код.

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

Регистр также важен, поскольку привязки чувствительны к регистру.

2 голосов
/ 01 апреля 2009

Попробуйте {Binding ComplexProp (0) .simpleSubProp}. Если это не сработает, вы также можете написать простой конвертер.

1 голос
/ 05 февраля 2010

Чтобы обобщить все это, я предлагаю вам использовать конвертер значений, как упоминалось другими, и использовать опцию ConverterParam для передачи индекса.

1 голос
/ 01 апреля 2009

В соответствии с синтаксисом пути на MSDN вы можете просто сделать:

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

Это может быть строчный "путь =", который дал вам ошибки? Попробуйте "Путь =". Кроме того, не уверен, что это работает в Silverlight ...

1 голос
/ 01 апреля 2009

Я не уверен, что вы можете сделать это. Обычно вы будете связывать список с чем-то вроде списка (или другого «повторяющегося» элемента управления), а затем каждый элемент внутри, который сможет связываться с соответствующим элементом в списке.

...