如何修复 Listviews 不呈现(正确)ObservableCollections,即使它们中有数据?

How do I fix Listviews not rendering (correctly) ObservableCollections even though they have data in it?

我正在构建一个具有 3 个功能和一个用于浏览它们的侧边菜单的应用程序。其中一项功能是带有 4 个显示项目的列表视图的 TabControl(在 4 个 TabItem 中)。

有两个主要问题:

¤ 首先,当我点击 "FEATURE3" 它显示 TabControl 但 ListViews 不渲染 甚至虽然我知道这些项目在 ObservableCollections 中。

BUT 如果我随后单击 "FEATURE2" 并返回 "FEATURE3",项目现在出现但仅针对 A 而不是 B C D。

如果我先点击 "FEATURE2" 然后点击 "FEATURE3" 它根本不会呈现。

¤ 我的第二个问题是,当我在 A 中添加项目时,它不会在列表视图中更新

这是我当前的代码:

MainWindow.xaml :

<Window x:Class="A.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:A"
        mc:Ignorable="d"
        Title="MainWindow"
        WindowStyle="None"
        WindowStartupLocation="CenterScreen"
        ResizeMode="NoResize">

    <Window.Resources>
        <DataTemplate x:Key="DataTemplate1">
            <Grid Width="100"
                  Height="30">
                <Grid.RowDefinitions>
                    <RowDefinition Height="8*"/>
                    <RowDefinition Height="1*"/>
                </Grid.RowDefinitions>
                <Image Source="{Binding Path=Image}" Grid.Row="0" Stretch="UniformToFill"/>
                <TextBlock Text="{Binding Path=Name}" Grid.Row="2" Foreground="Black"/>
            </Grid>
        </DataTemplate>
    </Window.Resources>

    <Grid>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*" />
            <ColumnDefinition Width="4*" />
        </Grid.ColumnDefinitions>

        <Grid Grid.Column="0"> <!--LEFT MENU-->

            <StackPanel VerticalAlignment="Top" Margin="20,20,20,0">
                <Button Name="FEATURE1Button" Content="FEATURE1" HorizontalContentAlignment="Left" Height="50" FontSize="24" Click="Click"/>
                <Button Name="FEATURE2Button" Content="FEATURE2" HorizontalContentAlignment="Left" Height="50" FontSize="24" Click="Click"/>
                <Button Name="FEATURE3Button" Content="FEATURE3" HorizontalContentAlignment="Left" Height="50" FontSize="24" Click="Click"/>
            </StackPanel>

        </Grid>

        <Grid Grid.Column="1"> <!--FEATURES-->

            <Grid Name="FEATURE1">
                <!-- FEATURE 1-->
            </Grid>

            <Grid Name="FEATURE2">
                <!-- Empty, not yet implemented-->
            </Grid>

            <Grid Name="FEATURE3">

                <TabControl>

                    <TabItem Header="A">
                        <ListView x:Name="ALB" ScrollViewer.HorizontalScrollBarVisibility="Disabled" 
                        Margin="10" ItemTemplate="{DynamicResource DataTemplate1}" 
                        Background="{x:Null}" BorderBrush="{x:Null}" Foreground="{x:Null}" Grid.Row="0">
                            <ListBox.ItemContainerStyle>
                                <Style TargetType="ListBoxItem">
                                    <Setter Property="Padding" Value="0"/>
                                    <Setter Property="Margin" Value="6"/>
                                </Style>
                            </ListBox.ItemContainerStyle>
                            <ListBox.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <WrapPanel/>
                                </ItemsPanelTemplate>
                            </ListBox.ItemsPanel>
                        </ListView>
                    </TabItem>

                    <TabItem Header="B">
                        <ListView x:Name="BLB" ScrollViewer.HorizontalScrollBarVisibility="Disabled" 
                        Margin="10" ItemTemplate="{DynamicResource DataTemplate1}" 
                        Background="{x:Null}" BorderBrush="{x:Null}" Foreground="{x:Null}" Grid.Row="0">
                            <ListBox.ItemContainerStyle>
                                <Style TargetType="ListBoxItem">
                                    <Setter Property="Padding" Value="0"/>
                                    <Setter Property="Margin" Value="6"/>
                                </Style>
                            </ListBox.ItemContainerStyle>
                            <ListBox.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <WrapPanel/>
                                </ItemsPanelTemplate>
                            </ListBox.ItemsPanel>
                        </ListView>
                    </TabItem>

                    <TabItem Header="C">
                        <ListView x:Name="CLB" ScrollViewer.HorizontalScrollBarVisibility="Disabled" 
                        Margin="10" ItemTemplate="{DynamicResource DataTemplate1}" 
                        Background="{x:Null}" BorderBrush="{x:Null}" Foreground="{x:Null}" Grid.Row="0">
                            <ListBox.ItemContainerStyle>
                                <Style TargetType="ListBoxItem">
                                    <Setter Property="Padding" Value="0"/>
                                    <Setter Property="Margin" Value="6"/>
                                </Style>
                            </ListBox.ItemContainerStyle>
                            <ListBox.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <WrapPanel/>
                                </ItemsPanelTemplate>
                            </ListBox.ItemsPanel>
                        </ListView>
                    </TabItem>

                    <TabItem Header="D">
                        <ListView x:Name="DLB" ScrollViewer.HorizontalScrollBarVisibility="Disabled" 
                        Margin="10" ItemTemplate="{DynamicResource DataTemplate1}" 
                        Background="{x:Null}" BorderBrush="{x:Null}" Foreground="{x:Null}" Grid.Row="0">
                            <ListBox.ItemContainerStyle>
                                <Style TargetType="ListBoxItem">
                                    <Setter Property="Padding" Value="0"/>
                                    <Setter Property="Margin" Value="6"/>
                                </Style>
                            </ListBox.ItemContainerStyle>
                            <ListBox.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <WrapPanel/>
                                </ItemsPanelTemplate>
                            </ListBox.ItemsPanel>
                        </ListView>
                    </TabItem>

                </TabControl>

            </Grid>
        </Grid>
    </Grid>
</Window>

MainWindow.xaml.cs :

namespace A
{
    public partial class MainWindow : Window
    {
        #region ATTRIBUTES
        Button[] Tabs;
        Grid[] Grids;
        bool[] loaded;

        const int nbTabs = 3;
        enum Features { FEATURE1 = 0, FEATURE2 = 1, FEATURE3 = 2 };

        FEATURE3 FEATURE3;
        #endregion

        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this;


            #region NAVIGATION SETUP
            Tabs = new Button[nbTabs];
            Grids = new Grid[nbTabs];
            loaded = new bool[nbTabs];

            Tabs[0] = FEATURE1Button;
            Grids[0] = FEATURE1;

            Tabs[1] = FEATURE2Button;
            Grids[1] = FEATURE2;

            Tabs[2] = FEATURE3Button;
            Grids[2] = FEATURE3;

            show((int)Features.FEATURE1, true);
            #endregion

            FEATURE3 = new FEATURE3();

            ALB.ItemsSource = FEATURE3.A;
            BLB.ItemsSource = FEATURE3.B;
            CLB.ItemsSource = FEATURE3.C;
            DLB.ItemsSource = FEATURE3.D;
        }

        #region NAVIGATION
        private void show(int index, bool showing)
        {
            FontWeight fw = FontWeights.Normal;
            Visibility vsb = Visibility.Collapsed;
            if (showing)
            {
                fw = FontWeights.Bold;
                vsb = Visibility.Visible;
                for (int i = (index + 1) % nbTabs; i != index; i = (i + 1) % nbTabs) show(i, false);
            }
            Tabs[index].SetValue(TextBlock.FontWeightProperty, fw);
            Grids[index].Visibility = vsb;
        }

        private void Click(object sender, RoutedEventArgs e)
        {
            for (int i = 0; i < Tabs.Length; i++)
                if (sender.Equals(Tabs[i]))
                {
                    show(i, true);

                    if (i == 0 && !loaded[i]) loadFEATURE1();
                    if (i == 1 && !loaded[i]) loadFEATURE2(); 
                    if (i == 2 && !loaded[i]) loadFEATURE3();

                    loaded[i] = true;

                    break;
                }
        }
        #endregion
        private async void loadFEATURE1()
        {
            //Loads FEATURE3, works perfectly
        }

        private async void loadFEATURE2()
        {
            //Currently empty, not yet implemented
        }

        private async void loadFEATURE3()
        {
            await FEATURE3.getAll(6);// gets 6 more items;
        }
    }

    public class FEATURE3 
    {
        // Items in a are also either b, c or d. Each item in a are also in one and only one of the 3 other ObservableCollection
        ObservableCollection<ITEM> a; 
        ObservableCollection<ITEM> b;
        ObservableCollection<ITEM> c;
        ObservableCollection<ITEM> d;

        public ObservableCollection<ITEM> A { get => a; set => a = value; }
        public ObservableCollection<ITEM> B { get => b; set => b = value; }
        public ObservableCollection<ITEM> C { get => c; set => c = value; }
        public ObservableCollection<ITEM> D { get => d; set => d = value; }

        public FEATURE3()
        {
            a = new ObservableCollection<ITEM>();
            b = new ObservableCollection<ITEM>();
            c = new ObservableCollection<ITEM>();
            d = new ObservableCollection<ITEM>();
        }


        public async Task getAll(int n)
        {
            //Fills a,b,c,d with n items. Works perfectly.
        }

    }

    public class ITEM
    {
        int id;
        string name;
        BitmapImage image;

        public int Id { get => id; set => id = value; }
        public string Name { get => name; set => name = value; }
        public BitmapImage Image { get => image; set => image = value; }
    }
}

我对我在哪里以及为什么会遇到这些问题一无所知。您对从哪里开始或解决此问题有任何提示吗? 谢谢。

编辑:我仍然不知道是什么导致了这个问题,但我使用 MVVM 架构修复了它

对于您的第二个问题,您的 class 需要实施 INotifyPropertyChanged 以便添加到您的 itemsource 的项目可以通知要更新的视图。 最简单的方法是安装 Fody 包 https://www.nuget.org/packages/Fody/ 它会为你注入 INotifyPropertyChanged

使用指南:https://github.com/Fody/Home/blob/master/pages/usage.md

非常容易使用。