如何在列表框中显示多个字典项
How to show multiple Dictionary items in ListBox
我的代码有两个列表框(LeftListBox
和 RightListBox
)和一个文本框。这些列表框在它们之间传输项目。 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);
}
}
}
}
Model/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]
这是什么意思?
很明显LeftListBoxItems在初始化MainWindow的构造函数时只有一项,所以只显示一项是正常的。
所以问题是您应该在 LeftListBoxItems 中放入 3 个项目,而不仅仅是一次(LeftListBoxItems.Add(Dic);)。
如果你想解决这个问题,也许你可以更改
ObservableCollection<Dictionary<string, Graph>>
到
ObservableCollection<KeyValuePair<string, Graph>>
,这样您就可以在应用上显示 3 个项目。
已更新
如果您想将 Dictionary 类型保留为您的集合 属性,您可以参考此 link WPF - How can I implement an ObservableCollection<K,T> with a key (like a Dictionary)? 来更改 ObservableCollection 类型。
由于您正在使用数据绑定,"proper" 处理此问题的方法是将文本和项目都包装在视图模型中:
public class GraphViewModel
{
public string Text { get; }
public Graph Graph { get; }
public GraphViewModel(string text, Graph graph) => (Text, Graph) = (text, graph);
}
不需要字典,您的 collection 可以改用这种类型:
public ObservableCollection<GraphViewModel> LeftListBoxItems { get; } = new ObservableCollection<GraphViewModel>();
public ObservableCollection<GraphViewModel> RightListBoxItems { get; } = new ObservableCollection<GraphViewModel>();
同样,将项目添加到字典只是为了立即将它们添加到 collection 没有意义,只需将它们直接添加到 collection:
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 也更容易。
我的代码有两个列表框(LeftListBox
和 RightListBox
)和一个文本框。这些列表框在它们之间传输项目。 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);
}
}
}
}
Model/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]
这是什么意思?
很明显LeftListBoxItems在初始化MainWindow的构造函数时只有一项,所以只显示一项是正常的。
所以问题是您应该在 LeftListBoxItems 中放入 3 个项目,而不仅仅是一次(LeftListBoxItems.Add(Dic);)。
如果你想解决这个问题,也许你可以更改
ObservableCollection<Dictionary<string, Graph>>
到
ObservableCollection<KeyValuePair<string, Graph>>
,这样您就可以在应用上显示 3 个项目。
已更新
如果您想将 Dictionary 类型保留为您的集合 属性,您可以参考此 link WPF - How can I implement an ObservableCollection<K,T> with a key (like a Dictionary)? 来更改 ObservableCollection 类型。
由于您正在使用数据绑定,"proper" 处理此问题的方法是将文本和项目都包装在视图模型中:
public class GraphViewModel
{
public string Text { get; }
public Graph Graph { get; }
public GraphViewModel(string text, Graph graph) => (Text, Graph) = (text, graph);
}
不需要字典,您的 collection 可以改用这种类型:
public ObservableCollection<GraphViewModel> LeftListBoxItems { get; } = new ObservableCollection<GraphViewModel>();
public ObservableCollection<GraphViewModel> RightListBoxItems { get; } = new ObservableCollection<GraphViewModel>();
同样,将项目添加到字典只是为了立即将它们添加到 collection 没有意义,只需将它们直接添加到 collection:
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 也更容易。