2014-01-22 3 views
0

Вот такая ситуация: у меня есть список объектов, каждый из которых ссылается на идентификационный номер. Я пытаюсь установить значение в столбце ListView на основе идентификационного номера объекта:Связывание - динамический выбор данных для столбца ListView

<ListView  Name="Listview1" 
       Itemsource="{Binding ObjectList}"> 
    <ListView.View> 
     <GridView> 
      <GridViewColumn Header="Header1" DisplayMemberBinding="{Binding subObject.property}"/> 
      <GridViewColumn Header="Header2" DisplayMemberBinding="{Binding PropertyOfAnItemInAList"/> 
     </GridView> 
    </ListView.View> 
</ListView> 

ObjectList это свойство в ViewModel, и доказывает ObservableCollection к ListView для обработки. Заголовки Header1 и Header2 привязаны к свойствам внутри элементов, найденных в ObservableCollection, которые называются ObjectList.

Все это отлично работает для Header1. Проблема заключается в том, что Header2 должен выбрать один элемент из списка, находящегося внутри каждого элемента ObservableCollection, и отобразить его на основе другого свойства ссылочных элементов в ObjectList.

Так как мне это сделать?

мне удалось получить его работу, установив переменную внутри объектов в ObjectList называется «currentSelection», которая затем устанавливается, когда связывание перебирает ObjectList от ItemSource для получения ListView:

public ObservableCollection<theObject> ObjectList { 

    get { 
     foreach (theObject obj in sourceCollection) { 

      obj.CurrentID = MyID; 
     } 

     return new ObservableCollection<theObject>sourceCollection // <-- secondary question: Is this the best way to send an observableCollection to a View??? 
    } 
} 

Однако это похоже на хак, а не на лучшую практику, так что есть другой, лучший способ сделать то же самое?

EDIT:

Вот отрывок из объектов внутри ObjectList, как у меня сейчас.

public class ObjectInObjectList { 

    /* constructor and various properties snipped to save space */ 

    private subObject subObj; 

    public int CurrentID {get; set;} 

    public SubObject { 

     get { return subObject; } // etc... 
    } 

    private SortedList<int,int> valuesIWantInSecondColumn 

    Public int PropertyOfAnItemInAList { 

     return valuesIWantInSecondColumn[currentID]; 
    } 
+0

Я не уверен, что я понимаю ваш вопрос. Вы просто ищете лучший способ получить MyID в столбце с заголовком Header1? –

+0

Я перечитал это и теперь думаю, что вы пытаетесь связать столбец «Header2» с разными свойствами в зависимости от того, какой элемент выбран в другом элементе управления, и вы сделали это, используя другое свойство с оператором switch (CurrentID), который возвращает определенное свойство в зависимости от по делу. Это точно? Можете ли вы показать соответствующий код для объекта? –

+0

Ли - это очень правильно. Я добавлю соответствующий код в редактирование вопроса. –

ответ

2

Я бы сбросил свойство CurrentID с объекта. Я не хочу иметь свойства пользовательского интерфейса в моих объектах домена. Я считаю, что лучшим решением является использование многосвязности для этого столбца и предоставление ему SortedList и вашего значения MyID из ViewModel, использование конвертера для возврата выбранного элемента из списка сортировки. Нечто подобное (при условии, перечисленных выпадающий а):

<ComboBox Grid.Column="0" ItemsSource="{Binding Ids}" SelectedItem="{Binding MyID}" /> 
    <ListView Name="Listview1" Grid.Column="1" ItemsSource="{Binding ObjectList}"> 
     <ListView.View> 
      <GridView> 
       <GridViewColumn Header="Header1" DisplayMemberBinding="{Binding subObject.property}"/> 
       <GridViewColumn Header="Header2" > 
        <GridViewColumn.DisplayMemberBinding> 
         <MultiBinding Converter="{StaticResource IDictionarySelector}"> 
          <Binding Path="PropertyOfAnItemInAList" /> 
          <Binding Path="DataContext.MyID" RelativeSource="{RelativeSource AncestorType={x:Type Window}}" /> 
         </MultiBinding> 
        </GridViewColumn.DisplayMemberBinding> 
       </GridViewColumn> 
      </GridView> 
     </ListView.View> 
    </ListView> 

Я тестировал этот код и пришлось добавить ToString() для возврата в противном случае он дает мне ошибку связывания, что TextBlock требуется строковое значение (спасибо Snoop):

public class IDictionarySelector : IMultiValueConverter 
{ 
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     if (values != null && values.Length == 2) 
     { 
      IDictionary idictionary = values[0] as IDictionary; 
      int? key = values[1] as int?; 

      if ((idictionary != null) && (key != null) && (idictionary.Contains(key))) 
      { 
       return idictionary[key].ToString(); 
      } 
     } 

     return null; 
    } 

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

Спасибо за это. (+1) Я попробую. Я также рассмотрю комментарий Шеридана ниже и посмотрю, стоит ли его включать. Я думаю, что Шеридан тоже хорошо. Если это сработает, я отмечу это как ответ. –

+0

Это работает очень хорошо. Спасибо. –

0

Вам просто нужно реализовать INotifyPropertyChanged Interface на свойства в вашем ObjectInObjectList классе. В частности, вы должны указать интерфейс, что PropertyOfAnItemInAList свойства изменилось, когда CurrentID свойства изменилось:

public int CurrentID 
{ 
    get { return currentID; } 
    set 
    { 
     currentID = value; 
     NotifyPropertyChanged("CurrentID"); 
     NotifyPropertyChanged("PropertyOfAnItemInAList"); 
    } 
} 

Это уведомление будет обновлять PropertyOfAnItemInAList свойства в пользовательском интерфейсе каждый раз, когда CurrentID свойства изменяется, так что вы не Нет необходимости в специальном виде Binding.

+0

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

+0

... подумайте об этом так: Два набора записей в клинике. Первый набор записей - это доктора, каждый из которых выполняет специализированную службу. Второй набор - пациенты. У каждого врача много пациентов, и у каждого пациента может быть несколько врачей. Предположим, что мы хотим, чтобы список показывал пациентам врача, и количество раз, когда каждый пациент посещал врача. Итак, в этом случае список, который у нас есть внутри объекта, - это идентификационный номер пациента как целое число для ключа, а значение - это количество раз, когда они были посещены. –

+1

Ты просто делаешь свою жизнь такой сложной. Если вы моделируете свое бизнес-правило с использованием иерархических данных, это значительно упростит ваш пользовательский интерфейс. Под этим я имею в виду объект «Доктор» и объект «Пациент» ... «Доктор» имел бы «ObservableCollection », а «Пациент» имел бы «ObservableCollection ». Используя WPF и MVVM, всегда проще всего предоставить * все * данные, необходимые в пользовательском интерфейсе *. – Sheridan

Смежные вопросы