我正在尝试实现一个包含特定类型项目的列表,一个会话。每个会话都包含一个包含Note类型的列表。我想在列表中的各个Session标题下显示这些Notes。
目前我尝试了两种不同的方法。第一种方法是将ItemsControls
用作ControlTemplate
ListBoxItems
。这是我在下面的图片中使用的,它是我希望列表看起来像。每个红色矩形显示一个Session,标题下面的项目是Notes。问题是,ListBox
的选择会选择ItemsControls
而不是每个单独的注释。
我尝试实现列表的另一种方法是为每个Note提供一个属性,告诉它属于哪个Session,以便在GroupStyle
上使用ListBox
。如果我然后将ListBox的ItemsSource设置为Notes而不是Sessions的列表,我将获得一个看起来像图片并且有选择注释的列表。现在的问题是我希望列表显示不包含任何Notes的Sessions。
有谁知道我应该用什么来实现一个带有选择的列表,并且按照我描述的方式工作?
答案 0 :(得分:3)
MainWindow.xaml:
<TreeView ItemsSource="{Binding}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:Session}" ItemsSource="{Binding Path=Notes}">
<TextBlock Text="{Binding Path=Name}" />
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type local:Note}">
<Expander Header="{Binding Path=Notek}">
<TextBlock Foreground="Red" Text="{Binding Path=Details}" />
</Expander>
</DataTemplate>
</TreeView.Resources>
</TreeView>
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
List<Session> sessions = new List<Session>();
for (int i = 0; i < 5; i++)
{
List<Note> notes = new List<Note>();
for (int j = i * 5; j < (i + 1) * 5; j++)
{
Note note = new Note()
{
Notek = string.Format("Note {0}", j),
Details = string.Format("Note j = {0}{1}j*j = {2}", j, System.Environment.NewLine, j*j)
};
notes.Add(note);
}
Session session = new Session()
{
Name = string.Format("Session # {0}", i),
Notes = notes
};
sessions.Add(session);
}
DataContext = sessions;
}
}
public class Session
{
public string Name { get; set; }
public List<Note> Notes { get; set; }
}
public class Note
{
public string Notek { get; set; }
public string Details { get; set; }
}
我认为您可以根据需要设置HierarchicalDataTemplate
的样式。我只是告诉你这个例子。我认为它更容易,而不是ItemsControl
与事件处理程序。
答案 1 :(得分:1)
要创建答案,我将假设以下数据模型:
class Session
{
public IEnumerable<Note> Notes { get; }
}
class Note { }
这需要一些编码来同步列表框。我创建了一个名为'ListBoxGroup'的附加属性。具有相同组名的所有列表框只能有一个共享的选定项。这是相当多的代码,所以它在底部。
需要注意的重要事项:列表框的列表框组在最初设置后无法更改,并且不支持删除项目,不检查空值等。因此,如果您需要更改运行时的会话应该从组中删除项目,检查是否从可视树中删除了列表框等等。
首先是页面的XAML:
xmlns:local="clr-namespace:YourApplication.YourNamespace"
<!-- ItemsControl does not have selection -->
<ItemsControl ItemsSource="{Binding SessionList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<!-- Header for the session -->
<Border Background="Gray">
<TextBlock Text="{Binding Name}" />
</Border>
<!-- listbox for notes -->
<ListBox ItemsSource="{Binding Notes}" local:ListBoxGroup.GroupName="Group1">
<ListBox.ItemTemplate>
<DataTemplate>
<!-- Template for a single note -->
<TextBlock Text="{Binding Description}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
下面是ListBoxGroup属性的C#代码:
public static class ListBoxGroup
{
public static string GetGroupName(DependencyObject obj)
{
return (string)obj.GetValue(GroupNameProperty);
}
public static void SetGroupName(DependencyObject obj, string value)
{
obj.SetValue(GroupNameProperty, value);
}
// Using a DependencyProperty as the backing store for GroupName. This enables animation, styling, binding, etc...
public static readonly DependencyProperty GroupNameProperty =
DependencyProperty.RegisterAttached("GroupName", typeof(string), typeof(ListBoxGroup), new UIPropertyMetadata(null, ListBoxGroupChanged));
private static Dictionary<string, List<ListBox>> _listBoxes = new Dictionary<string, List<ListBox>>();
private static void ListBoxGroupChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
string newValue = e.NewValue as string;
ListBox listBox = obj as ListBox;
if (newValue == null || listBox == null) return;
if (_listBoxes.ContainsKey(newValue))
{
_listBoxes[newValue].Add(listBox);
}
else
{
_listBoxes.Add(newValue, new List<ListBox>() { listBox });
}
listBox.SelectionChanged += new SelectionChangedEventHandler(listBox_SelectionChanged);
listBox.PreviewKeyUp += new System.Windows.Input.KeyEventHandler(listBox_KeyUp);
}
static void listBox_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
{
ListBox listBox = sender as ListBox;
if (e.Key == System.Windows.Input.Key.Up && listBox.SelectedIndex == 0)
{
//move to previous
string groupName = GetGroupName(listBox);
List<ListBox> group = _listBoxes[groupName];
int senderIndex = group.IndexOf(listBox);
if (senderIndex != 0)
{
listBox.SelectedItem = null;
ListBox beforeSender = group[senderIndex - 1];
int index = beforeSender.Items.Count - 1;
beforeSender.SelectedIndex = index;
var container = beforeSender.ItemContainerGenerator.ContainerFromIndex(index);
(container as FrameworkElement).Focus();
}
}
else if (e.Key == System.Windows.Input.Key.Down
&& listBox.SelectedIndex == listBox.Items.Count - 1)
{
//move to next
string groupName = GetGroupName(listBox);
List<ListBox> group = _listBoxes[groupName];
int senderIndex = group.IndexOf(listBox);
if (senderIndex != group.Count - 1)
{
listBox.SelectedItem = null;
ListBox afterSender = group[senderIndex + 1];
afterSender.SelectedIndex = 0;
var container = afterSender.ItemContainerGenerator.ContainerFromIndex(0);
(container as FrameworkElement).Focus();
}
}
}
static void listBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems.Count > 0)
{
ListBox listBox = sender as ListBox;
string groupName = GetGroupName(listBox);
foreach (var item in _listBoxes[groupName])
{
if (item != listBox)
{
item.SelectedItem = null;
}
}
}
}
}