2011-12-19 74 views
0

我正在設置一個ListView,其Source屬性被設置爲我的一個類的ivar,名爲Cat使用CollectionViewSource實現ListView - 不刷新?

每個CatTraitObservableCollection對象:

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集合的更改不會導致UI正確更新。例如,這樣的:

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

似乎並沒有產生任何影響在UI立即,但如果我重置Source屬性,像這樣:正確

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

然後ListView更新。但是,我確定必須有一些我錯過的東西,因爲我希望界面在添加/刪除項目時進行更新。

編輯:CollectionViewSource被應用於ListView在我的XAML文件:

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

... 

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

CollectionViewSource如何設置爲ListView? – Tyrsius 2011-12-19 23:49:42

+0

@Tyrsius新增。 – 2011-12-20 00:39:28

+0

@craig關於「這是多餘的嗎?一個比另一個好嗎?」評論:'_traits'是一個私人成員,不需要傳遞給'OnPropertyChanged' - 畢竟,沒有任何綁定它來接收更新通知。 'OnPropertyChanged(「Traits」);'就足夠了。 – 2011-12-20 01:01:55

回答

-4

查看本演示,瞭解如何讓ListView綁定連接並適用於所有CRUD操作。

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

+0

這非常完美。感謝您將它們放在一起,我已經掠過了它,這正是我所尋找的。 – 2012-02-10 14:30:18

+2

上面的鏈接已經死機 – cppguy 2016-04-25 18:54:05

+0

需要回答,而不是指向鏈接無效的答案的鏈接。 – 2017-08-30 01:02:10

0

我似乎現在不能找到它,但我似乎記得一些問題,結合CollectionViewSource。您是否嘗試過直接綁定到CurrentCat.Traits並在代碼隱藏中設置this.DataContext = this(我假設您沒有在這裏使用MVVM)?

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

感謝您的幫助,但我仍然無法成功連接點。據我所知,我沒有使用MVVM,我對C#和WPF很陌生。從我發佈的代碼以及我見過的MVVM的其他示例中,我確信我正在做其他事情。 :) – 2011-12-21 14:16:29

+0

完全按照我發佈的設置綁定,並在代碼隱藏的加載部分中設置'this.DataContext = this'。看看是否有效。 – Tyrsius 2011-12-21 23:03:17

0

而不是直接綁定到CollectionViewSource,並更換其Source強制刷新,我相信你想綁定到CVS的View財產......

<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類的私有成員通常被稱爲「場」,而不是「高德「(Objective-C背景?:))
  • this關鍵字加前綴類成員通常是多餘的,除非有其它範圍標識符與同名
  • 這是值得探討的MVVM和相關模式,如果你會做什麼不平凡在WPF中;它們可以幫助您保持視圖(XAML對象)儘可能輕鬆且易於更改。

    就你而言,例如,我假設你展示的代碼來自任何Window或UserControl包含你的ListView的代碼隱藏。遵循MVVM模式將涉及創建一個單獨的「ViewModel」類,該類將包含Traits集合並通過CollectionViewSource(使用View屬性,如我所述)公開它。然後,您的UserControl將擁有指定爲其DataContext的ViewModel實例,並且可以將ListView綁定到公開的CollectionView。

+0

奇怪的是,我的'CollectionViewSource'的'View'屬性沒有'Refresh()'方法 – 2011-12-21 20:30:03

+0

*很奇怪,因爲'CollectionViewSource.View'屬性的類型是'ICollectionView',它確實有一個Refresh()方法](http://msdn.microsoft.com/en-us/library/system.componentmodel.icollectionview.aspx)...如果您在該Click事件中調試並中斷,那麼'this.CollectionViewSource定義了View的屬性? – 2011-12-21 20:59:09

+0

我有一個CollectionViewSource類似的問題,拒絕更新像它應該的,並且這個答案導致null refrence異常,因爲CollectionViewSource的View屬性始終爲空。 – 2017-08-30 01:34:01

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>