ObservableCollection 停止与 WPF Listbox 一致更新

问题描述 投票:0回答:1

我正在使用 WPF,并且有一个列表框,我已在后面的代码中将其绑定到 ObservableCollection。 它显示在多个视图中,并且工作完美(添加/删除,并在视图之间保持同步),直到我尝试向列表项添加图标。 现在,当将项目添加到 ObservableCollection 时,它甚至不会一致地将项目添加到列表框中。 我试图更改的不仅仅是在列表框中显示项目的名称,当项目“监视”属性为 true 时,我希望它在名称旁边显示图像,并在监视属性为 false 时删除该图像。 这部分正在工作,图标出现并被正确删除。 为了使此图标正确显示,我通过添加 ListBox.ItemTemplate->DataTemplate 修改了我的 xaml,如下所示。

以前的 XAML:

 <ListBox
                    Name="CameraTargetsListbox"
                    Style="{DynamicResource NeuronListBoxStyle}" 
                    VerticalAlignment="Stretch"
                    HorizontalAlignment="Stretch"
                    HorizontalContentAlignment="Stretch"
                    VerticalContentAlignment="Stretch"
                    Margin="0,8,0,4"
                    Height="140"
                    ItemContainerStyle="{DynamicResource NeuronListBoxItem_CameraTargets}"/>

当前的 XAML:

 <ListBox
     Name="CameraTargetsListbox"
     Style="{DynamicResource NeuronListBoxStyle}" 
     VerticalAlignment="Stretch"
     HorizontalAlignment="Stretch"
     HorizontalContentAlignment="Stretch"
     VerticalContentAlignment="Stretch"
     Margin="0,8,0,4"
     Height="140"
     ItemContainerStyle="{DynamicResource NeuronListBoxItem_CameraTargets}">
     <ListBox.ItemTemplate>
         <DataTemplate>
             <StackPanel Orientation="Horizontal">
                 <ContentPresenter 
                                   Content="{Binding MonitoringItemIcon,  UpdateSourceTrigger=PropertyChanged}"  
                                   Margin="-4,0,10,0" />
                 <TextBlock Text="{Binding DisplayName, UpdateSourceTrigger=PropertyChanged}" />
             </StackPanel>
         </DataTemplate>
     </ListBox.ItemTemplate>
 </ListBox>

我应该注意,我添加了“UpdateSourceTrigger=PropertyChanged”以尝试解决问题,但没有什么区别。

然后在后面的代码中我链接了 ObservableCollection,这段代码没有任何改变:

public CameraTargetsControl()
{            
    InitializeComponent();
    this.DataContext = this;
    
    CameraTargetsListbox.ItemsSource = PropertyList;
...

由于某种原因,由于我更改了列表框以显示模板而不是允许其默认显示信息,因此列表框无法一致更新。 现在,当我添加一个项目时,有时它会显示在列表框中,有时则不会。 如果我查看另一个视图,它将显示添加的项目,但有时项目会添加为空白(例如,正确列出第一个项目,然后是空白项目(列表框中没有文本,只有空格),然后添加第三个项目。我一生都无法弄清楚为什么该列表在视图之间不再同步,甚至在当前视图中也没有更新我已经阅读了很多有关使用 IPropertyChanged 的内容,但我不明白为什么。我应该需要在这里实现这个,因为可观察集合应该处理这个问题,事实上,直到我尝试更新列表项模板为止,如果它完全损坏,我可以看到需要 PropertyChanged 通知,但它仍然有效。 ..有时。

感谢所有帮助。 这是我用来更新列表的代码,基本上每次添加/删除项目时都会收到一个新列表,该列表会根据 ObservableCollection(PropertyList)进行检查并处理更新。

           _ = Dispatcher.BeginInvoke(() => 
           {
               List<int> addList = new();
               List<int> deleteList = new();
               List<(int, int)> updateList = new(); // index from incoming list, index from listbox

               CameraTarget selectedTarget = null;

               CameraTargetsListbox.SelectionChanged -= CameraTargetsListbox_SelectionChanged;

               if (CameraTargetsListbox.SelectedIndex != -1) selectedTarget = (CameraTarget)CameraTargetsListbox.SelectedItem;
               
               // Check for additions and deletions
               foreach (var target in targetList)
               {
                   bool found = false;
                   foreach (var listedTarget in PropertyList)
                   {
                       if (target.Class == CameraTarget.TargetClass.AIS)
                       {
                           if (listedTarget.MMSI == target.MMSI)
                           {
                               updateList.Add((targetList.IndexOf(target), PropertyList.IndexOf(listedTarget)));
                               found = true;
                               break;
                           }
                       }
                       else if (listedTarget.TargetIndex == target.TargetIndex)
                       {
                           updateList.Add((targetList.IndexOf(target), PropertyList.IndexOf(listedTarget)));
                           found = true;
                           break;
                       }
                   }
                   if (!found) { addList.Add(targetList.IndexOf(target)); }                    
               }

               // Check for deletions
               foreach (var listedTarget in PropertyList)
               {
                   bool found = false;
                   foreach (var target in targetList)
                   {
                       if (target.Class == CameraTarget.TargetClass.AIS)
                       {
                           if (listedTarget.MMSI == target.MMSI)
                           {
                               found = true;
                               break;
                           }
                       }
                       else if (listedTarget.TargetIndex == target.TargetIndex)
                       {
                           found = true;
                           break;
                       }
                   }
                   if (!found) deleteList.Add(PropertyList.IndexOf(listedTarget));
               }

               if (updateList.Count > 0)
               {
                   foreach (var index in updateList)
                   {
                       if (index.Item2 == CameraTargetsListbox.SelectedIndex)
                       {
                           if (PropertyList[index.Item2].Monitoring && PropertyList[index.Item2].MonitoringItemIcon == null)
                           {
                               PropertyList.RemoveAt(index.Item2);
                               PropertyList.Insert(index.Item2, targetList[index.Item1]);
                           }
                           else PropertyList[index.Item2] = targetList[index.Item1];
                           CameraTargetsListbox.SelectedIndex = index.Item2;
                           RefreshSelectedInfo();
                       }
                       else if(PropertyList[index.Item2].Monitoring && PropertyList[index.Item2].MonitoringItemIcon == null)
                       {
                           PropertyList.RemoveAt(index.Item2);
                           PropertyList.Insert(index.Item2, targetList[index.Item1]);
                       }
                       // Capture name updates
                       else if (PropertyList[index.Item2].ToString() != targetList[index.Item1].ToString())
                       {
                           PropertyList.RemoveAt(index.Item2);
                           PropertyList.Insert(index.Item2, targetList[index.Item1]);
                       }
                       else PropertyList[index.Item2] = targetList[index.Item1];

                   }
               }
               if (deleteList.Count > 0)
               {
                   foreach (int index in deleteList)
                   {
                       if (index == CameraTargetsListbox.SelectedIndex) DeleteSelectedTarget(null, null);
                       else PropertyList.RemoveAt(index); 
                   }
               }
               if (addList.Count > 0)
               {
                   foreach (int index in addList)
                   {
                       PropertyList.Add(targetList[index]);
                   }
               }
               
               CameraTargetsListbox.SelectionChanged += CameraTargetsListbox_SelectionChanged;
               CheckPropertyList();
           });

这是我第一次发布问题,所以请让我知道我还能提供什么:)

c# wpf user-interface listbox observablecollection
1个回答
0
投票

ObservableCollection 将在项目发生更改时发出通知。但是 item 中的属性也需要通知才能调用 ui 更新。 例如:也许您需要更改“DisplayName”属性通知。确保您的“PropertyList item”模型是“INotifyPropertyChanged”。 您可以了解有关“mvvm 模式”或“绑定声明概述”或“INotifyPropertyChanged 接口”的更多信息。

© www.soinside.com 2019 - 2024. All rights reserved.