2016-12-28 4 views
0

У меня возникает одна проблема с привязкой SelectedItems элемента управления ListView, для ее решения у меня есть расширенный элемент управления ListView, ListViewExtended, чтобы открыть SelectedItemsList, используя ссылку из этого post, но двусторонняя привязка не работает получить SelectedItems в модели.ListView SelectedItems Реализация DataBinding в MVVM

Просьба не указывать проблему в этом демо-источнике.

таможенного контроля:

public sealed class ListViewExtended : ListView 
{ 
    public ListViewExtended() 
    { 
     this.SelectionChanged += ListViewExtended_SelectionChanged; 
    } 

    void ListViewExtended_SelectionChanged(object sender, SelectionChangedEventArgs e) 
    { 
     this.SelectedItemsList = this.SelectedItems; 
    } 

    #region SelectedItemsList 

    public IEnumerable SelectedItemsList 
    { 
     get { return (IEnumerable)GetValue(SelectedItemsListProperty); } 
     set { SetValue(SelectedItemsListProperty, value); } 
    } 

    public static readonly DependencyProperty SelectedItemsListProperty = 
      DependencyProperty.Register("SelectedItemsList", 
      typeof(IEnumerable), 
      typeof(ListViewExtended), 
      new FrameworkPropertyMetadata(null)); 

    #endregion 
} 

Модель:

public class Member 
{ 
    public string Name { get; set; } 
    public int Age { get; set; } 
} 

public class Family : BindableBase 
{ 
    private string _name; 
    public string Name 
    { 
     get { return _name; } 
     set { _name = value; OnPropertyChanged("Name"); } 
    } 

    private IList<Member> _selectedMembers; 
    public IList<Member> SelectedMembers 
    { 
     get { return _selectedMembers; } 
     set { _selectedMembers = value; OnPropertyChanged("SelectedMembers"); } 
    } 

    public override string ToString() 
    { 
     return Name; 
    } 
} 

ViewModel:

public class ListViewSelectedItemsExtendedViewModel : BindableBase 
{ 
    Dictionary<string, IEnumerable> _repository = new Dictionary<string, IEnumerable>(); 

    public ListViewSelectedItemsExtendedViewModel() 
    { 
     var families = new List<Family>(); 
     families.Add(new Family() { Name = "family 1" }); 
     families.Add(new Family() { Name = "family 2" }); 
     Families = families; 

     var items = new List<Member>(); 
     items.Add(new Member() { Name = "John", Age = 30 }); 
     items.Add(new Member() { Name = "Chapel", Age = 50 }); 
     items.Add(new Member() { Name = "Max", Age = 46 }); 
     _repository.Add(families[0].Name, items); 

     items = new List<Member>(); 
     items.Add(new Member() { Name = "Warner", Age = 28 }); 
     items.Add(new Member() { Name = "Peter", Age = 36 }); 
     items.Add(new Member() { Name = "Tom", Age = 5 }); 
     _repository.Add(families[1].Name, items); 
    } 

    private IList<Family> _families; 
    public IList<Family> Families 
    { 
     get { return _families; } 
     set { _families = value; OnPropertyChanged("Families"); } 
    } 

    private Family _selectedFamily; 
    public Family SelectedFamily 
    { 
     get { return _selectedFamily; } 
     set { _selectedFamily = value; OnPropertyChanged("SelectedFamily"); } 
    } 

    private ICommand _familySelectionChangedCommand; 
    public ICommand FamilySelectionChangedCommand 
    { 
     get 
     { 
      return _familySelectionChangedCommand ?? (_familySelectionChangedCommand = new DelegateCommand(
       () => 
       { 
        Members = (IList<Member>)_repository[SelectedFamily.Name]; 
       } 
      )); 
     } 
    } 
} 

XAML:

<Grid> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="1*" /> 
     <ColumnDefinition Width="3*" /> 
    </Grid.ColumnDefinitions> 
    <ListBox ItemsSource="{Binding Families}" SelectedItem="{Binding SelectedFamily}"> 
     <i:Interaction.Triggers> 
      <i:EventTrigger EventName="SelectionChanged"> 
       <i:InvokeCommandAction Command="{Binding FamilySelectionChangedCommand}" /> 
      </i:EventTrigger> 
     </i:Interaction.Triggers> 
    </ListBox> 
    <Grid Grid.Column="1"> 
     <Grid.RowDefinitions> 
      <RowDefinition /> 
      <RowDefinition /> 
      <RowDefinition Height="Auto" /> 
     </Grid.RowDefinitions> 
     <fsx:ListViewExtended Margin="10" Grid.Row="0" 
          ItemsSource="{Binding Members}" 
          SelectedItemsList="{Binding SelectedFamily.SelectedMembers, Mode=TwoWay}"> 
      <ListView.View> 
       <GridView> 
        <GridViewColumn Header="Include"> 
         <GridViewColumn.CellTemplate> 
          <DataTemplate> 
           <CheckBox IsChecked="{Binding Path=IsSelected, 
           RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListViewItem}}}" /> 
          </DataTemplate> 
         </GridViewColumn.CellTemplate> 
        </GridViewColumn> 
        <GridViewColumn Header="Name" Width="120" DisplayMemberBinding="{Binding Name}" /> 
        <GridViewColumn Header="Age" Width="50" DisplayMemberBinding="{Binding Age}" /> 
       </GridView> 
      </ListView.View> 
      <!--<i:Interaction.Behaviors> 
      <fsx:ListViewMultiSelectionBehavior 
       SelectedItems="{Binding SelectedFamily.SelectedMembers}" /> 
     </i:Interaction.Behaviors>--> 
     </fsx:ListViewExtended> 
     <ListView Margin="10" Grid.Row="1" 
       ItemsSource="{Binding SelectedFamily.SelectedMembers}"> 
      <ListView.View> 
       <GridView> 
        <GridViewColumn Header="Name" Width="120" DisplayMemberBinding="{Binding Name}" /> 
        <GridViewColumn Header="Age" Width="50" DisplayMemberBinding="{Binding Age}" /> 
       </GridView> 
      </ListView.View> 
     </ListView> 
    </Grid> 
</Grid> 

Помимо выше реализации, я также попытался использовать подход, приведенные в данном post, но не повезло, чтобы получить 100% результат.

+0

В моем опыте IEnumerable не подходит для реализации двухсторонней привязки данных. Попробуйте использовать IList или даже ObservableCollection. –

+0

Я уже пытался использовать IList на ранней стадии, но не повезло. –

+1

@Furqan Я столкнулся с той же проблемой. Это проблема, которая вызывает проблему. Закончился с использованием 'IEnumerable' как в представлении (Custom Control), так и в viewmodel. – Funk

ответ

0

Проблема заключается в том, что вы не можете установить свойство источника общего типа IList <Member> на не-общий IList, который является типом свойства SelectedItems ListView. Если вы попробуете это сами, вы заметите, что он не будет даже скомпилировать:

IList<Member> members = listView1.SelectedItems; //WON'T COMPILE 

Родовое IList <T> интерфейс не расширяет IList интерфейс, так это два совершенно разных типов. Это похоже на попытку установить свойство int в строку. Это просто не сработает.

Если изменить тип свойства SelectedMembers вашего семейного класса к необщего IList он будет работать:

public class Family : BindableBase 
{ 
    private string _name; 
    public string Name 
    { 
     get { return _name; } 
     set { _name = value; OnPropertyChanged("Name"); } 
    } 

//change the type here: 
    private IList _selectedMembers; 
    public IList SelectedMembers 
    { 
     get { return _selectedMembers; } 
     set { _selectedMembers = value; OnPropertyChanged("SelectedMembers"); } 
    } 

    public override string ToString() 
    { 
     return Name; 
    } 
} 

должен быть каким-то образом обобщить его, как и другие встроенные в контрольной DependencyProperty работа с коллекциями

Как упоминалось; для того, чтобы вы могли установить свойство source в значение свойства SelectedItems ListView, тип источника источника должен соответствовать типу свойства SelectedItems, то есть свойство источника должно быть не общим идентификатором IList.

Вы также можете прочитать следующее: https://blog.magnusmontin.net/2014/01/30/wpf-using-behaviours-to-bind-to-readonly-properties-in-mvvm/. Речь идет о том, как привязываться к свойствам только для чтения с использованием поведения. Тип свойств должен соответствовать, хотя независимо от того, какое решение вы решите принять.

+0

IList расширяет IEnumerable, 'общедоступный интерфейс IList : ICollection , IEnumerable , IEnumerable' –

+0

Вы правы, но проблема в том, что вы пытаетесь присвоить IList свойство к IList стоимости, и это не будет работать. Ваш пользовательский «SelectedItemsList» действительно является IEnumerable, но свойство * source *, к которому он привязан, является IList . Я уточнил свой ответ, чтобы уточнить. – mm8

+0

Опять IList может быть назначен IList. –

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