【问题标题】:WPF list binding failsWPF 列表绑定失败
【发布时间】:2017-05-07 23:04:34
【问题描述】:

我已按照here 的指示进行操作。尽管如此,我的绑定似乎失败了,因为我的窗口中没有结果。我想要做的只是将列表项绑定到 ListView。 XAML 文件内容:

<Window x:Class="IV_sem___PwSG___WPF_task1.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:IV_sem___PwSG___WPF_task1"
    mc:Ignorable="d"
    Title="MainWindow" Height="600" Width="800"
    MinHeight="500" MinWidth="500">
<Window.Resources>
    <DataTemplate x:Key="MyItemTemplate">
        <Grid Margin="5" Background="Aqua">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <TextBlock Text="{Binding Name}" Grid.Column="0" Grid.Row="0"
                       FontSize="18" FontFamily="Arial"></TextBlock>
            <TextBlock Text="{Binding Description}" Grid.Column="0" Grid.Row="1"
                       FontSize="14" FontFamily="Arial"></TextBlock>
            <TextBlock Text="{Binding Category}" Grid.Column="0" Grid.Row="2"
                       FontSize="12" FontFamily="Arial"></TextBlock>
            <TextBlock Text="{Binding Price}" Grid.Column="1" Grid.RowSpan="1"></TextBlock>
            <Button Content="Add to cart" Grid.Column="2" Grid.Row="1"/>
        </Grid>
    </DataTemplate>
</Window.Resources>
<!--<Window.DataContext>
    <local:MainWindow />
</Window.DataContext>-->

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>

    <Menu Grid.Column="0" Grid.Row="0">
        <MenuItem Header="File">
            <MenuItem Header="Load"/>
            <MenuItem Header="Save"/>
            <Separator/>
            <MenuItem Header="Exit" Click="ExitMenuItem_Click"/>
        </MenuItem>
        <MenuItem Header="Products">
            <MenuItem Header="Add products" Click="AddProductMenuItem_Click"/>
            <MenuItem Header="Clear products"/>
        </MenuItem>
        <MenuItem Header="About" Click="AboutMenuItem_Click"/>
    </Menu>

    <TabControl Grid.Column="0" Grid.Row="1">
        <TabItem Header="Shop">
            <!--<Grid>-->
            <ListView ItemsSource="{Binding itemList}"
                      ItemTemplate="{StaticResource MyItemTemplate}"/>
            <!--</Grid>-->
        </TabItem>
        <TabItem Header="Warehouse">

        </TabItem>
    </TabControl>
</Grid>

.cs文件内容:

namespace IV_sem___PwSG___WPF_task1{
public partial class MainWindow : Window
{
    public List<Item> itemList { get; set; }

    public MainWindow()
    {
        itemList = new List<Item>();
        InitializeComponent();
    }

    private void AboutMenuItem_Click(object sender, RoutedEventArgs e)
    {
        MessageBox.Show("This is simple shop manager.", "About application", MessageBoxButton.OK, MessageBoxImage.Information);
    }

    private void ExitMenuItem_Click(object sender, RoutedEventArgs e)
    {
        this.Close();
    }

    public class Item
    {
        string Name { get; set; }
        string Description { get; set; }
        Category Category { get; set; }
        double Price { get; set; }
        public Item(string a, string b, Category c, double d)
        {
            Name = a; Description = b; Category = c; Price = d;
        }

    }

    private void AddProductMenuItem_Click(object sender, RoutedEventArgs e)
    {
        itemList.Add(new Item("Computer", "Computer's description", Category.Electronics, 2499.99));
        itemList.Add(new Item("Apple", "Apple's description", Category.Food, 1.99));
        itemList.Add(new Item("Computer", "Computer's description", Category.Electronics, 2499.99));
    }
}

public enum Category
{
    Electronics, Food
}
}

Category 是一个枚举类型。 List 是 MainWindow 类的属性。 它应该根据上面的链接工作。

【问题讨论】:

  • 您绑定到 DataContext 中任何对象的属性“itemList”。项目列表在哪里?它存在吗?什么是数据上下文?或者换句话说:您的 ListView.ItemsSource 绑定的绑定源是否真的存在?
  • @elgonzo itemList 在MainWindow() 构造函数中初始化,并填充了一些元素。 DataContext 肯定是包含 MainWindow 类的命名空间,因为它是迄今为止我项目中唯一的命名空间。我尝试在 .cs 中将 itemList 分配给 this.DataContext 并在 XAML 中仅使用 "{Binding}" 而不是 "{Binding itemList}" - 这无论如何都没有区别。我可以再给你一些代码吗?
  • 请。显示 itemList 是什么集合类型,填充它的位置和方式,以及为窗口设置 DataContext 的位置/方式。用这些信息扩展你的问题(不要试图在 cmets 中解释它......)
  • 我是否忽略了它,但是您在哪里为您的窗口设置 DataContext?我看到它在 XAML 中被注释掉了...
  • 我刚才概述的问题场景与绑定或数据上下文无关。您的困惑可能是由于尚未习惯(我承认有些丑陋)XAML 语法。当您的程序最终评估 XAML 的这部分 &lt;local:MainWindow/&gt; 以呈现 UI 时,它会指示您的程序创建 MainWindow 对象(即new MainWindow();)。就像&lt;Button/&gt; 会指示您的程序创建一个 Button 对象...

标签: c# wpf xaml


【解决方案1】:

问题中的代码存在三个问题。

1. ListView.ItemsSource 绑定

程序没有为 ListView 或其父容器之一设置 DataContext。所以&lt;ListView ItemsSource="{Binding itemList}" ... /&gt;中的绑定无法解析。

由于 itemList 是 MainWindow 本身的属性,因此我建议将 MainWindow DataContext 绑定到 MainWindow 本身:

<Window x:Class="IV_sem___PwSG___WPF_task1.MainWindow"
    ...
    ...
    x:Name="Self"
    DataContext="{Binding ElementName=Self}"
>


2.项目列表

itemList 只是一个简单的List&lt;T&gt; 集合。 List&lt;T&gt; 没有内置机制来通知 ListView 和绑定引擎,无论何时将项目添加到列表中或从列表中删除。当程序在 AddProductMenuItem_Click 处理程序中将项目添加到 itemList 时,ListView 不会更新,因为它没有被通知 itemList 已更改。

修复相当简单:使用ObservableCollection&lt;T&gt; 而不是List&lt;T&gt;。 ObservableCollection 提供有关项目添加和删除的通知。 WPF 可以理解这些通知,并允许 ListView 在集合发生更改时刷新其视图。


3.物品类

itemList 集合包含Item 对象。 ListView 使用的项目模板中的 UI 元素绑定到这些 Item 对象的属性。但是,Item 类的属性不是公开的。如果这些属性不是公开的,则绑定到这些属性会失败。

同样,修复相当简单:将所有参与绑定的属性公开。

【讨论】:

  • “我建议将 MainWindow DataContext 绑定到 MainWindow 本身” - 是不是 MainWindow 的 DataContext 默认设置为自身?
  • 属性未公开!这就是问题所在......现在它似乎正在工作。
  • 关于DataContext:DataContext默认没有值(为null)。我在回答中提出的快速修复(将 DataContext 绑定到 UI 元素)是您在 WPF 中很少做的事情。正如名称“数据上下文”所暗示的那样,您通常会将 DataContext 设置为一个对象,该对象提供各个 UI 元素所关注的数据(无论是在表示+交互方面)。通常,UI 元素不是数据本身,因此默认情况下让 DataContext 指向它所属的 UI 元素是没有意义的。
  • 关于 DataContext 的一些附加说明:DataContext - 以及 WPF UI 元素的其他属性 - 不是普通属性。它们就是 WPF 所说的“依赖属性”。依赖属性的一个方面是它们可以从其父容器/UI 元素的相同属性继承值。 DataContext 就是这样一个表现出这种行为的 DP。请注意,已为 MainWindow UI 元素设置了 DataContext。 ListView 的 DataContext 属性(让我们暂时忽略项目模板)根本没有设置,绑定仍然没有问题解决。 (1/2)
  • (2/2) 这怎么可能? ListView ItemsSource 的绑定是否访问 MainWindow 的 DataContext 属性。否。绑定仅访问 ListView 的 DataContext 属性。但是没有人设置 ListView 的 DataContext 属性。但是,由于 DataContext 是一个继承依赖属性,它从其父容器 (TabItem/TabControl) 继承 DataContext。此父容器 DataContext 再次从其父 DataContext 继承......等等,直到继承链最终到达已显式设置 DataContext 的 MainWindow。
【解决方案2】:

使用 Observable 集合代替 List 如下

public ObservableCollection<Item> itemList { get; set; }

因为 Observable Collection 使用 INotifyCollectionChanged 实现,INotifyPropertyChanged 它是通知集合更改事件并更新 UI。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-18
    • 2018-01-21
    • 1970-01-01
    • 1970-01-01
    • 2015-01-23
    • 1970-01-01
    相关资源
    最近更新 更多