无法让 WPF .NET 5.0 ListView 项目显示在控件中

Unable to get WPF .NET 5.0 ListView items to show up in the control

我的应用程序中有几个 ListView 项,我以编程方式向其中添加了项。不幸的是,什么都没有出现。我现在尝试将 ItemSource 绑定到 List<SystemInfoItem> 列表但无济于事。

我进行了详尽的 Internet 搜索以弄清楚如何使其工作,但无济于事。我还没想出神奇的查询。

此外,我正在尝试更改 header 和行的 header 背景颜色和前景色。

这是我的 xaml:

<ListView Grid.Row="1" x:Name="VnaInfoBox" Height="160" Margin="0,10,0,10" Width="400" Foreground="White" Background="Transparent" 
          ItemsSource="{Binding VnaSysInfoItems}">
    <GridView>
        <GridViewColumn x:Name="vnaInfoItemCol" Header="Item" Width="150" DisplayMemberBinding="{Binding Item}"/>
        <GridViewColumn x:Name="vnaInfoValueCol" Header="Value" Width="250" DisplayMemberBinding="{Binding Value}"/>
    </GridView>
</ListView>

这里是 SystemInfoItem class:

的代码
public class SystemInfoItem
{
    public string Item { get; set; }
    public string Value { get; set; }
}

而且,这是我将项目添加到绑定列表的代码:

VnaSysInfoItems.Add(new SystemInfoItem() { Item = "Manufacturer", Value = VnaContainer.VnaSS.Vna_IDManuf });

[...] I add items to programmatically.
[...] I've now tried binding the ItemSource to a List<SystemInfoItem> list to no avail.

是的,这是预期的行为。 ListList<T> 和其他集合类型没有实现任何通知用户界面更改的机制。换句话说,用户界面无法知道您何时通过添加、插入或删除项来修改集合。会怎样?

对于集合类型,有 INotifyCollectionChanged interface that signals changes to the collection using the CollectionChanged event. The good news is, that you do not have to implement it yourself, there is already a built-in type that supports notifying collection changes using this interface. It is called ObservableCollection<T>。用这种类型替换你的 List<T>,它应该可以工作。

public ObservableCollection<SystemInfoItem> VnaSysInfoItems { get; }

属性也是如此。截至目前,用户界面也不会检测到对项目属性 ItemValue 的更改。在那里,您可以 implement the INotifyPropertyChanged 界面使用 PropertyChanged 事件向 属性 发出信号变化。

public class SystemInfoItem : INotifyPropertyChanged
{
   private string _item;
   private string _value;

   public string Item
   {
      get => _item;
      set
      {
         if (_item == value)
            return;

         _item = value;
         OnPropertyChanged();
      }
   }

   public string Value
   {
      get => _value;
      set
      {
         if (_value == value)
            return;
         
         _value = value;
         OnPropertyChanged();
      }
   }

   public event PropertyChangedEventHandler PropertyChanged;

   protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
   {
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
   }
}

VnaSysInfoItems 的类型更改为 ObservableCollection<SystemInfoItem>。与 List<T> 不同,添加到 ObservableCollection<T> 的 objects 会通知 UI.

Also, I'm trying to change the header background color and the foreground color for both the headers and rows.

设置GridViewColumnHeaderContainerStyle来改变headers的背景和前景:

<GridView>
    <GridView.ColumnHeaderContainerStyle>
        <Style TargetType="GridViewColumnHeader">
            <Setter Property="Foreground" Value="Green" />
            <Setter Property="Background" Value="Yellow" />
        </Style>
    </GridView.ColumnHeaderContainerStyle>
    <GridViewColumn x:Name="vnaInfoItemCol" Header="Item" Width="150" DisplayMemberBinding="{Binding Item}"/>
    <GridViewColumn x:Name="vnaInfoValueCol" Header="Value" Width="250" DisplayMemberBinding="{Binding Value}"/>
</GridView>

要更改行的前景,您可以设置 ListView 控件本身的 Foreground 属性(就像您已经完成的那样)。

感谢@mm8 和@thatguy 提供正确的选择!

显然,不使用 MVVM 是不好的,但是,我正在将一个现有的复杂测试和测量应用程序从 WinForms 移植到 WPF .NET 5.0,因此我需要使用旧的机制实现第一个移植版本,这样我就更有可能推出新版本。我将在首次发布 WPF 版本并实施 MVVM 后返回。它在某些地方可用,但不是在整个应用程序中可用。

我最终找到了如下解决方案:

  1. 我在每个 GridViewColumns 的 ListView 和 DataTemplate 中添加了一个 ListView.View:

                <ListView Grid.Row="1" x:Name="VnaInfoBox" Height="160" Margin="0,10,0,10" Width="400" Foreground="White" Background="Transparent">
                    <ListView.View>
                        <GridView>
                            <GridViewColumn Header="Item" Width="150">
                                <GridViewColumn.CellTemplate>
                                    <DataTemplate>
                                        <ContentControl Content="{Binding Item}" />
                                    </DataTemplate>
                                </GridViewColumn.CellTemplate>
                            </GridViewColumn>
                            <GridViewColumn Header="Value" Width="240" DisplayMemberBinding="{Binding Value}">
                                <GridViewColumn.CellTemplate>
                                    <DataTemplate>
                                        <ContentControl Content="{Binding Value}" />
                                    </DataTemplate>
                                </GridViewColumn.CellTemplate>
                            </GridViewColumn>
                        </GridView>
                    </ListView.View>
                </ListView>
    
  2. 我使用了一个在运行时构建的列表,因为 ListView 中的项目发生变化并分配给 ListView.ItemsSource:

         // Create the VnaInfoBox data source
         List<SystemInfoItem> vnaInfo = new List<SystemInfoItem>();
    
          vnaInfo.Add(new SystemInfoItem() { Item = "Manufacturer", Value = "Ford" });
          vnaInfo.Add(new SystemInfoItem() { Item = "Model", Value = "Model A" });
          vnaInfo.Add(new SystemInfoItem() { Item = "Serial #", Value = "23456" });
          vnaInfo.Add(new SystemInfoItem() { Item = "Version", Value = "3.4" });
          vnaInfo.Add(new SystemInfoItem() { Item = "Options", Value = "Convertable" });
    
          VnaInfoBox.ItemsSource = vnaInfo;