2014-03-04 30 views
0

我使用.NET 4.0和曾在我的代码像下面WPF投掷警告在.net变更4.5.1

public Dictionary<DirectoryInfo, ObservableCollection<Media>> FoldersDictionary 

我使用这本字典的显示文件夹中的一个Dictionary从表面列表框中的Windows目录中。 DirectoryInfo将包含有关文件夹的目录信息,例如它们的名称和Media类将包含这些文件夹内的数据。

当我添加或删除我的DictionaryObservableCollection项目,WPF向我扔这样的警告:

Collection of type 'System.Collections.Generic.Dictionary`2[[System.IO.DirectoryInfo, 
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089], 
[System.Collections.ObjectModel.ObservableCollection`1[[Media, ViewModel, 
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], System, Version=4.0.0.0, 
Culture=neutral, PublicKeyToken=b77a5c561934e089]]' has been changed without raising 
a CollectionChanged event. Support for this is incomplete and inconsistent, 
and will be removed completely in a future version of WPF. Consider either (a) 
implementing INotifyCollectionChanged, or (b) avoiding changes to this type of 
collection`. 

但是我忽略了这一警告是我的输出是显示正常的了。昨天我在Windows 7上升级到.Net 4.5.1并运行此代码。警告仍然是相同的,但现在每次刷新我的字典(意味着清除它,然后向ObservableCollection添加新东西),最后的ObservableCollection项目在我的UI上永远不可见。我调试了我的代码,发现Dictionary infact仍然添加了最后一项,只是它没有显示在我的WPF XAML UI上。我想知道可能是这种行为是由于我看到的警告。我采取了以下CollectionChanged事件我的代码:

private void OnUrlChanged(string newUrl) 
     { 
      if (string.IsNullOrEmpty(newUrl)) 
       return; 

      var directoryInfo = new DirectoryInfo(newUrl); 
      DirectoryInfo[] directoryInfos = directoryInfo.GetDirectories(); 

      if (directoryInfos.Any()) 
      { 
       if (FoldersDictionary != null && FoldersDictionary.Any()) 
       { 
        FoldersDictionary.Clear(); 
       } 

       FoldersDictionary = null; 
       FoldersDictionary = new Dictionary<DirectoryInfo, ObservableCollection<Media>>(); 
       LoadFolders(FoldersDictionary, directoryInfos); 
      }  
     } 

private void LoadFolders(Dictionary<DirectoryInfo, ObservableCollection<Media>> Folders, IEnumerable<DirectoryInfo> directoryInfos) 
     { 
      foreach (DirectoryInfo item in directoryInfos) 
      { 
       ObservableCollection<Media> medias = LoadMedias(item.FullName); 

       //new code starts here 
      medias.CollectionChanged+=new System.Collections.Specialized.NotifyCollectionChangedEventHandler(medias_CollectionChanged); 
       //new code ends here 

       if (medias != null) 
       { 
        Folders.Add(item, medias); 
       } 
      } 
     } 

//new code starts here 
     void medias_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) 
     { 
      //do nothing 
     } 

//new code ends here 

DictionaryPropertyChanged给出如下:

 public const string FoldersDictionaryPropertyName = "FoldersDictionary"; 

     private Dictionary<DirectoryInfo, ObservableCollection<Media>> _foldersDictionary; 

     public Dictionary<DirectoryInfo, ObservableCollection<Media>> FoldersDictionary 
     { 
      get { return _foldersDictionary; } 

      set 
      { 
       if (_foldersDictionary == value) 
       { 
        return; 
       } 

       Dictionary<DirectoryInfo, ObservableCollection<Media>> oldValue = _foldersDictionary; 
       _foldersDictionary = value; 



       RaisePropertyChanged(FoldersDictionaryPropertyName); 


      } 
     } 

这是我使用了XAML。

<Grid Height="180"> 
        <s:SurfaceListBox x:Name="xFoldersListBox" 
             Background="{x:Null}" 
             ItemContainerStyle="{StaticResource        SurfaceListBoxItemSquareStyle}" 
             ItemsSource="{Binding FoldersDictionary}" 
             ItemTemplate="{StaticResource FolderDataTemplate}" 
             SelectedValuePath="Value" 
             Template="{StaticResource SurfaceListBoxHorizontalTemplate}" /> 
</Grid> 


<DataTemplate x:Key="FolderDataTemplate"> 
      <s:SurfaceToggleButton IsChecked="{Binding IsSelected, 
                 Mode=TwoWay, 
                 RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type s:SurfaceListBoxItem}}}" Style="{StaticResource ToggleButtonStyle}"> 
       <TextBlock Text="{Binding Path=Key.Name}" 
          TextAlignment="Center" 
          TextWrapping="Wrap" /> 
      </s:SurfaceToggleButton> 
</DataTemplate> 

但我仍然得到同样的警告,之前还更我不能看到我的最后一个文件夹在我的字典,当我清晰显示和重新填充我的Dictionary。任何想法可能会导致这种行为?

回答

1

当您重新创建FoldersDictionary的另一个实例时,代码有问题。如果你只是清除词典并重新填充它,那么代码按预期工作,也没有警告。

但我不知道为什么最后一个目录丢失,我进入代码,发现键/值对是正确的。正如警告所暗示的,可能Dictionary不是用来像数据绑定中的ObservableCollection一样使用的。

private void OnUrlChanged(string newUrl) 
{ 
    if (string.IsNullOrEmpty(newUrl)) 
     return; 

    //instantiate only once 
    if (FoldersDictionary == null) 
    { 
     FoldersDictionary = new Dictionary<DirectoryInfo, ObservableCollection<Media>>(); 
    } 
    else if (FoldersDictionary.Any()) 
    { 
     FoldersDictionary.Clear(); 
    } 

    var directoryInfo = new DirectoryInfo(newUrl); 
    DirectoryInfo[] directoryInfos = directoryInfo.GetDirectories(); 

    if (directoryInfos.Any()) 
    {     
     LoadFolders(FoldersDictionary, directoryInfos); 
    } 
} 
+0

谢谢你。我会修改我的代码。你是对的,在“升级到.Net 4.5.1”之后,UI中的最后一个元素丢失了,这是完全奇怪的,因为我可以看到.Net 4.0中的所有元素。可能是微软在他们的框架中做了一些改变,我无法弄清楚他们改变了什么。 – azmuhak

0

您正在将FoldersDictionary绑定到UI元素。为了让WPF将所有内容串起来,FoldersDictionary应该会引发PropertyChanged事件。如警告所示,执行INotifyPropertChanged接口并将事件处理程序附加到此属性。

+0

我在我的代码中添加了PropertyChanged。请参阅我的原始文章中的编辑 – azmuhak

+0

而且它不像我在输出UI中看不到任何文件夹。当使用.net 4.5.1时,最后的项目总是缺失。在.net 4.0中根本没有问题。 – azmuhak

1

根据警告提示,Dictionary类型不执行INotifyCollectionChanged。您需要创建实现接口的定制Dictionary以使其工作。

或者您可以尝试使用this blog postObservableDictionary。它是自定义执行IDictionary<TKey,TValue>接口,与INotifyCollectionChangedINotifyPropertyChanged接口相结合。

+0

但是那么为什么一切工作在.NET 4.0? .Net4.5.1中导致我的词典的最后一项没有出现在UI中的变化?对此有何想法? – azmuhak

+0

你在时机方面得到了(非)幸运,或者其他事情正在触发你的绑定更新。不管它是什么,_it都不重要。你的代码被破坏了。如果您可以提供帮助,请勿根据无意的副作用创建生产代码。始终与发布的界面工作。在Microsoft .net库(如BCL和WPF)中尤其如此,因为发布的界面非常详细。 –