【问题标题】:How to show multiple Dictionary items in ListBox如何在列表框中显示多个字典项
【发布时间】:2020-03-12 20:39:35
【问题描述】:

我的代码有两个列表框(LeftListBoxRightListBox)和一个文本框。这些列表框在它们之间传输项目。 TextBox显示一个数字,对应RightListBox中的SelectedItem(例如,选择T1时显示10,选择T2时显示20,以此类推)。

我刚刚成功了!! ...但是那些 ListBoxes只显示第一个字典项三分之二...我怎样才能显示所有这些?

这是我的代码:

MainWindow.xaml

<Window x:Class="ListBoxMoveAll.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:ListBoxMoveAll"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="600">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="2*" />
            <ColumnDefinition Width="80" />
            <ColumnDefinition Width="2*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="2*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <ListBox x:Name="LeftListBox" Grid.Row="0" Grid.RowSpan="3" Grid.Column="0"
            ItemsSource="{Binding LeftListBoxItems}" DisplayMemberPath="Key" SelectedValuePath="Value"
            SelectionMode="Extended" Margin="0,10"/>
        <StackPanel Grid.Column="1" Grid.Row="0" VerticalAlignment="Center">
            <Button Content="Add" x:Name="Add_Button" Click="Add_Button_Click"/>
        </StackPanel>
        <StackPanel Grid.Column="1" Grid.Row="2" VerticalAlignment="Center">
            <Button Content="Remove" x:Name="Remove_Button" Click="Remove_Button_Click"/>
        </StackPanel>
        <ListBox x:Name="RightListBox" Grid.Row="0" Grid.RowSpan="3" Grid.Column="2"
            ItemsSource="{Binding RightListBoxItems}" DisplayMemberPath="Key" SelectedValuePath="Value"
            SelectionMode="Extended" Margin="0,10"/>

        <StackPanel Grid.Column="4" Grid.Row="1" Grid.RowSpan="1" Margin="0,10">
            <TextBox Text="{Binding SelectedValue.Step, ElementName=RightListBox}"/>
        </StackPanel>
    </Grid>
</Window>

MainWindow.xaml.cs

using ListBoxMoveAll.Model;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;

namespace ListBoxMoveAll
{
    public partial class MainWindow : Window
    {
        public ObservableCollection<Dictionary<string, Graph>> LeftListBoxItems { get; } 
            = new ObservableCollection<Dictionary<string, Graph>>();
        public ObservableCollection<Dictionary<string, Graph>> RightListBoxItems { get; } 
            = new ObservableCollection<Dictionary<string, Graph>>();

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

            Dictionary<string, Graph> Dic = new Dictionary<string, Graph>();
            Dic.Add("T1", new Graph(10));
            Dic.Add("T2", new Graph(20));
            Dic.Add("T3", new Graph(30));

            LeftListBoxItems.Add(Dic);

            // Yes! There are three items in Dic!
            foreach (var item in Dic)
            {
                MessageBox.Show(item.ToString());
            }
        }

        private void Add_Button_Click(object sender, RoutedEventArgs e)
        {
            //foreach (TestModel item in LeftListBox.SelectedItems.OfType<TestModel>().ToList())
            foreach (Dictionary<string, Graph> item 
                in LeftListBox.SelectedItems.OfType<Dictionary<string, Graph>>().ToList())
            {
                LeftListBoxItems.Remove(item);
                RightListBoxItems.Add(item);
            }
        }

        private void Remove_Button_Click(object sender, RoutedEventArgs e)
        {
            foreach (Dictionary<string, Graph> item 
                in RightListBox.SelectedItems.OfType<Dictionary<string, Graph>>().ToList())
            {
                RightListBoxItems.Remove(item);
                LeftListBoxItems.Add(item);
            }
        }
    }
}

模型/Graph.cs

namespace ListBoxMoveAll.Model
{
    public class Graph
    {
        public Graph(int step) { Step = step; }

        public int Step { get; set; }
    }
}

由于 foreach 语句显示 Dic 中有三个项目,我认为我的 XAML 有问题,但我无法弄清楚。你们可能知道问题出在哪里。对不起,如果这是一个非常基本的问题......提前谢谢你。

新发现:我为 LeftListBoxItems 添加了另一个 foreach 语句:

foreach (var item in LeftListBoxItems)
            {
                MessageBox.Show(item.ToString());
            }

...输出只有一次,内容为:

System.Collections.Generic.Dictionary`2[System.String,ListBoxMoveAll.Model.Graph]

这是什么意思?

【问题讨论】:

    标签: c# wpf xaml dictionary listbox


    【解决方案1】:

    由于您使用的是数据绑定,因此“正确”的处理方式是将文本和项目都包装在视图模型中:

    public class GraphViewModel
    {
        public string Text { get; }
        public Graph Graph { get; }
    
        public GraphViewModel(string text, Graph graph) => (Text, Graph) = (text, graph);
    }
    

    不需要字典,您的收藏可以使用这种类型:

        public ObservableCollection<GraphViewModel> LeftListBoxItems { get; } = new ObservableCollection<GraphViewModel>();
        public ObservableCollection<GraphViewModel> RightListBoxItems { get; } = new ObservableCollection<GraphViewModel>();
    

    同样,将项目添加到字典中只是在之后立即将它们添加到集合中是没有意义的,只需将它们直接添加到集合中:

    LeftListBoxItems.Add(new GraphViewModel("T1", new Graph(10)));
    LeftListBoxItems.Add(new GraphViewModel("T2", new Graph(20)));
    LeftListBoxItems.Add(new GraphViewModel("T3", new Graph(30)));
    

    对每个按钮处理程序的小改动:

    foreach (var item in LeftListBox.SelectedItems.Cast<GraphViewModel>().ToList())
    ... and ...
    foreach (var item in RightListBox.SelectedItems.Cast<GraphViewModel>().ToList())
    

    最后,将您的列表框DisplayMemberPath 属性绑定到Text 并去掉SelectedValuePath

    <ListBox x:Name="LeftListBox" Grid.Row="0" Grid.RowSpan="3" Grid.Column="0"
        ItemsSource="{Binding LeftListBoxItems}" DisplayMemberPath="Text"
        SelectionMode="Extended" Margin="0,10"/>
    
    <ListBox x:Name="RightListBox" Grid.Row="0" Grid.RowSpan="3" Grid.Column="2"
        ItemsSource="{Binding RightListBoxItems}" DisplayMemberPath="Text"
        SelectionMode="Extended" Margin="0,10"/>
    

    这类似于 Genos Loser 的第二个示例,但视图模型比 KeyValuePair 更安全,并且如果您需要,以后添加 INPC 也更容易。

    【讨论】:

    • 现在可以了!不过,我不得不将 TextBox Binding 更改为 &lt;TextBox Text="{Binding SelectedValue.Graph.Step, ElementName=RightListBox}"/&gt;。非常感谢!
    【解决方案2】:

    很明显LeftListBoxItems在初始化MainWindow的构造函数时只有一项,所以只显示一项是正常的。

    所以问题是您应该在 LeftListBoxItems 中放置 3 个项目,而不仅仅是一次(LeftListBoxItems.Add(Dic); )。

    如果你想解决问题,也许你可以改变

    ObservableCollection<Dictionary<string, Graph>>
    

    ObservableCollection<KeyValuePair<string, Graph>>
    

    ,这样您就可以在应用程序上显示 3 个项目。

    更新

    如果您想保留 Dictionary 类型作为您的集合属性,您可以参考此链接WPF - How can I implement an ObservableCollection<K,T> with a key (like a Dictionary)? 更改 ObservableCollection 类型。

    【讨论】:

    • 谢谢,但我应该从Dictionary&lt;string, Graph&gt; 更改为KeyValuePair&lt;string, Graph&gt; 多远?他们都是?然后,我在Dic.Add("T1", new Graph(10)); 收到了CS1061: 'KeyValuePair&lt;string, Graph&gt;' does not contain a definition for 'Add' 错误。你知道如何解决这个问题吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-17
    相关资源
    最近更新 更多