如何修复 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
非常容易使用。
我正在构建一个具有 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
非常容易使用。