使用WPF在列表框中绑定字典的键和值

17
我想将字典的键绑定到ListBox中的一行,将字典的值绑定到另一行。键的类型是Book,这是我编写的一个类,值的类型是int。我想在网格中写入类的元素和整数值。你能帮我吗?我对确定itemsSource和要绑定的数据类型感到很困惑。谢谢帮忙。
编辑:我忘了说我正在使用C# - WPF. =)
我将字典作为itemsSource发送,并在objectdataprovider标记中指定字典类型,并尝试使用以下代码发送值(int):
< TextBlock Text="{Binding Value, Mode=OneWay}" Grid.Row="1" Width="65" >

选定项显示为[myNameSpace.Book, 4]而不是仅仅是4。


BookListBox.ItemsSource = LibManager.Books;

这是我在 Window.xaml.cs 中编写的代码,其中 Books 是一个 BookList,而 BookList 是一个 dictionary<Book, int> 类型。

以及 XAML 文件:

< ListBox Height="571" HorizontalAlignment="Left" Margin="444,88,0,0"
          Name="BookListBox" VerticalAlignment="Top" Width="383" >
        < ListBox.Resources>
            <ObjectDataProvider x:Key="BookData"
                                ObjectType="{x:Type local:BookList}"/>
        </ListBox.Resources>
        < ListBox.ItemTemplate>
            < DataTemplate>
                < Border BorderThickness="2" BorderBrush="Black" Margin="5"
                         CornerRadius="5" Width="350" >
                    < Grid DataContext="{StaticResource BookData}" >
                        < Grid.ColumnDefinitions>
                            < ColumnDefinition/>                        
                        </Grid.ColumnDefinitions>
                        < Grid.RowDefinitions>
                            < RowDefinition/>
                            < RowDefinition/>
                        < /Grid.RowDefinitions>
                        < Label Content="count: " />
                        < TextBlock Text="{Binding Value, Mode=OneWay}"
                                    Grid.Row="1" Width="65"/>
                    < /Grid>
                < /Border>
            < /DataTemplate>
        < /ListBox.ItemTemplate>
    < /ListBox>
我的代码还有一个问题-- 我看不到列表框中列出的项目。我的意思是,我可以通过 ListBox.SelectedItem 获取值,但无法在列表框中看到。因此,我不能确定是否能将整数值传递到我想要的位置。
因此,我认为我首先需要解决这个问题...我手写了一个标签,另一个标签应该在同一行中通过数据绑定填充,但我只能看到第一个标签,但我可以在后台代码中访问该值。

你使用的是哪种语言/框架?听起来像是.NET,但你应该澄清一下。 - LukeH
Cemre,你能和我们分享你的代码吗? - Serkan Hekimoglu
2个回答

41

以下代码将显示以下内容:

1
Book 1
-------
2
Book 2
-------
3
Book 3

SelectedBookIndex将被设置为所选书籍的索引,初始情况下将选择第二本书。

XAML:

<Window x:Class="TestDemo.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="300" Width="300">

    <StackPanel>
        <ListBox 
            ItemsSource="{Binding Path=Books}"
            SelectedValuePath="Value"
            SelectedValue="{Binding Path=SelectedBookIndex}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Border BorderBrush="Black" BorderThickness="2">
                        <StackPanel>
                            <TextBlock Text="{Binding Path=Value}" />
                            <TextBlock Text="{Binding Path=Key.Name}" />
                        </StackPanel>
                    </Border>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </StackPanel>
</Window>

后台代码:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;

namespace TestDemo
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            Books = new Dictionary<Book, int>();
            Books.Add(new Book() { Name = "Book 1"}, 1);
            Books.Add(new Book() { Name = "Book 2" }, 2);
            Books.Add(new Book() { Name = "Book 3" }, 3);

            SelectedBookIndex = 2;

            DataContext = this;
        }

        public Dictionary<Book, int> Books { get; set; }

        private int _selectedBookIndex;
        public int SelectedBookIndex
        {
            get { return _selectedBookIndex; }
            set
            {
                _selectedBookIndex = value;
                Debug.WriteLine("Selected Book Index=" + _selectedBookIndex);
            }
        }
    }

    public class Book
    {
        public string Name { get; set; }
    }
}

我无法这样做。为什么? - Ana
2
这个解决方案将不再起作用,因为您必须将字典更改为ObservableDictionary(它必须实现INotifyCollectionChanged和INotifyPropertyChanged)。 - Ahm3d Said
1
"{Binding Path=Key.Name}" 对我来说无效,但"{Binding Path=Key}"行得通。该字典在ObservableCollection中,并且文本位于DataTemplate中。 - dvdhns

0

从Grid元素中删除DataContext = "{StaticResource BookData}"

ObjectDataProvider将创建一个新的、空的BookList,而您的TextBlock将继承该DataContext。如果您删除该属性,则TextBlock将从ItemsControl中的当前项获取其DataContext,该项将是该行的KeyValuePair。由于您正在使用代码创建数据,因此可能可以完全删除ObjectDataProvider元素。


但是我不应该实现对象类型吗? - cemregoksu
@cemregoksu:我不确定你所说的“实现对象类型”是什么意思。你不需要向WPF提供任何类型信息;它会从对象的运行时类型中读取它。如果你想使用方法调用或提供构造函数参数在XAML中创建一个对象,可以使用ObjectDataProvider。由于你已经有了一个对象,所以你可以直接将它分配给ItemsSource。 - Quartermeister

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接