2011-12-19 3 views
0

Я работаю над созданием ListView, чье свойство Source установлено на ivar моего класса, называемого Cat.Реализация ListView с CollectionViewSource - не освежает?

Каждого Cat имеет ObservableCollection из Trait объектов:

private ObservableCollection<Trait> _traits = new ObservableCollection<Trait>(); 

public ObservableCollection<Trait> Traits 
{ 
get 
    { 
     return _traits; 
    } 
} 

public void AddTrait(Trait t) 
{ 
    _traits.Add(t); 
    // Is this redundant? Is one better than the other? 
    this.OnPropertyChanged("_traits"); 
    this.OnPropertyChanged("Traits"); 
} 

public IEnumerator<Object> GetEnumerator() 
{ 
    return _traits.GetEnumerator(); 
} 

А потом я возложение Source свойства этой Traits коллекции:

this.CollectionViewSource.Source = CurrentCat.Traits; 

Это работает должным образом, и Trait объектов правильно отображается в моем ListView.

Вопрос заключается в том, что внесение изменений в этот базовый набор _traits не приводит к правильному обновлению пользовательского интерфейса. Например, это: Не кажется

void AddTraitButton_Click(object sender, RoutedEventArgs e) 
{ 
    if (this.CurrentCat != null) 
    { 
     this.CurrentCat.AddTrait(new Trait()); 
    } 
} 

не иметь никакого эффекта сразу в пользовательском интерфейсе, но если я сбросить Source свойства следующим образом:

var oldSource = this.CollectionViewSource.Source; 
this.CollectionViewSource.Source = null; 
this.CollectionViewSource.Source = oldSource; 

Затем ListView обновления правильно. Но, я уверен, должно быть что-то, что мне не хватает, так как я бы хотел, чтобы пользовательский интерфейс обновлялся после добавления/удаления элемента.

Edit:CollectionViewSource прикладывается к ListView в моем файле XAML:

<CollectionViewSource x:Name="CollectionViewSource" x:Key="CollectionViewSource" /> 

... 

<ListView x:Name="ItemListView" ItemsSource="{Binding Source={StaticResource CollectionViewSource}}" ... 
+0

Как установить CollectionViewSource в ListView? – Tyrsius

+0

@ Добавлен Тирсиус. –

+0

@craig Что касается «Это избыточно? Это лучше, чем другое?» comment: '_traits' является частным членом и не нуждается в передаче в OnPropertyChanged. В конце концов, для получения уведомления об обновлении не может быть ничего связанного с ним. 'OnPropertyChanged (« Черты »);' будет достаточно. –

ответ

-4

Ознакомьтесь с этой демонстрацией, которую я поставил перед тем, как связать привязку ListView и работать для всех операций CRUD.

http://www.flaskofespresso.com/2012/01/windows-8-metro-app-listview-binding-and-editing/

+0

Это невероятно отлично. Спасибо, что собрали это вместе, я просмотрел его, и это именно то, что я искал. –

+2

Ссылка выше мертва – cppguy

+0

Нужен ответ, а не ссылка на ответ, для которого ссылка в любом случае мертва. –

0

Я не могу найти его сейчас, но я помню, какая-то проблема с привязкой к CollectionViewSource. Вы пробовали привязать напрямую к CurrentCat.Traits и установить this.DataContext = this в код-сзади (я предполагаю, что вы здесь не используете MVVM)?

<ListView x:Name="ItemListView" ItemsSource="{Binding CurrentCat.Traits}" /> 
+0

Спасибо за вашу помощь, но я до сих пор не смог успешно соединить точки. Я не использую MVVM, насколько я знаю, я очень новичок в C# и WPF. Из кода, который я опубликовал, и других примеров MVVM, которые я видел, я уверен, что я делаю что-то еще. :) –

+0

Установите привязку точно так же, как я ее разместил, и установите 'this.DataContext = this' в разделе загрузки кода. Посмотрите, работает ли это. – Tyrsius

0

Вместо привязки к CollectionViewSource непосредственно и заменив его Source, чтобы заставить обновления, я полагаю, вы хотите привязать к View имущества CVS в ...

<ListView x:Name="ItemListView" 
      ItemsSource="{Binding Source={StaticResource CollectionViewSource}, Path=View}" ... 

... и называть CollectionViewSource.Refresh() после обновления исходной коллекции.

void AddTraitButton_Click(object sender, RoutedEventArgs e) 
{ 
    if (this.CurrentCat != null) 
    { 
     this.CurrentCat.AddTrait(new Trait()); 
     this.CollectionViewSource.Refresh(); 
    } 
} 

Кроме того, пара заметок, так как вы, кажется, относительно новой конвенции .NET/WPF:

  • Частные члены классов .NET, как правило, называют «полями», а не «Ивар «(Объектив-C фона?:))
  • члены класса префиксов с this ключевого слова обычно является излишним, если нет другого идентификатора в области видимости с тем же именем
  • Это стоит исследовать образцы MVVM и связанные с ними, если вы будете делать что-нибудь нетривиальное в WPF; они помогают вам сохранять ваши взгляды (объекты XAML) такими же легкими и легко изменяемыми, насколько это возможно.

    В вашем случае, например, я предполагаю, что код, который вы указали, находится в кодовом коде любого окна или UserControl, содержащего ListView. После шаблона MVVM будет создан отдельный класс «ViewModel», который будет содержать коллекцию Traits и выставить ее через CollectionViewSource (используя свойство «Вид», как я уже упоминал). Тогда ваш UserControl будет иметь экземпляр ViewModel, назначенный как его DataContext, и ListView может быть привязан к открытому CollectionView.

+0

Странно, что свойство 'View' моего' CollectionViewSource' не имеет метода 'Refresh()' –

+0

Это * * странно, поскольку свойство 'CollectionViewSource.View' имеет тип' ICollectionView', который [действительно имеет метод Refresh()] (http://msdn.microsoft.com/en-us/library/system.componentmodel.icollectionview.aspx) ... Если вы отлаживаете и ломаете это событие Click, то как это выглядит. this.CollectionViewSource Свойство «Свойство просмотра» определено? –

+0

У меня есть аналогичная проблема с CollectionViewSource, который отказывается обновлять, как и предполагалось, и этот ответ вызывает исключение null refrence, потому что свойство View CollectionViewSource всегда равно null. –

0

Вы можете работать только с ObservableCollection еще. Хотя есть одна проблема - она ​​не отображает данные в IsInDesignMode. Возможно, в будущем это улучшится.

public class MainViewModel : ViewModelBase 
{ 
... 
    private ObservableCollection<PartViewModel> _parts; 
    public ObservableCollection<PartViewModel> Parts 
    { 
     get 
     { 
      if (_parts == null) 
      { 
       _parts = new ObservableCollection<PartViewModel>(); 
       _parts.CollectionChanged += _parts_CollectionChanged; 
      } 
      return _parts; 
     } 
    } 

    object m_ReorderItem; 
    int m_ReorderIndexFrom; 
    void _parts_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) 
    { 
     switch (e.Action) 
     { 
      case NotifyCollectionChangedAction.Remove: 
       m_ReorderItem = e.OldItems[0]; 
       m_ReorderIndexFrom = e.OldStartingIndex; 
       break; 
      case NotifyCollectionChangedAction.Add: 
       if (m_ReorderItem == null) 
        return; 
       var _ReorderIndexTo = e.NewStartingIndex; 
       m_ReorderItem = null; 
       break; 
     } 
    } 

    private PartViewModel _selectedItem; 
    public PartViewModel SelectedItem 
    { 
     get 
     { 
      return _selectedItem; 
     } 
     set 
     { 
      if (_selectedItem != value) 
      { 
       _selectedItem = value; 
       RaisePropertyChanged("SelectedItem"); 
      } 
     } 
    } 
    ... 

    #region ViewModelBase 

    public override void Cleanup() 
    { 
     if (_parts != null) 
     { 
      _parts.CollectionChanged -= _parts_CollectionChanged; 
     } 
     base.Cleanup(); 
    } 

    #endregion 

    } 

<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> 
    <Grid.Resources> 
     <CollectionViewSource x:Name="PartsCollection" Source="{Binding Parts}"/> 
    </Grid.Resources> 

    <ListView Margin="20" CanReorderItems="True" CanDragItems="True" AllowDrop="True" 
       ItemsSource="{Binding Source={StaticResource PartsCollection}}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}" SelectionMode="Single"> 
     <ListView.ItemContainerStyle> 
      <Style TargetType="ListViewItem"> 
       <Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter> 
      </Style> 
     </ListView.ItemContainerStyle> 
     <ListView.ItemTemplate> 
     ... 
     </ListView.ItemTemplate> 
    </ListView> 
</Grid>