我的目标是创建一个组合框,该组合框在打开时显示任何字符串列表(因此是标准行为),但是当用户选择其中一个字符串时,它将被添加到列表顶部的“最近使用过”下方分隔符。
本质上,我想要一个行为与在MS Word中选择字体的控件完全一样的控件:
我的第一步是创建一个具有附加Dependency属性的自定义控件,该属性包含最近选择的项。当用户从列表中选择一个项目时,此列表将更新。我不想修改项目的原始列表,因为我的目标是获得一个可重用的控件,使用户不必自己管理最新的项目。
private static readonly DependencyPropertyKey LastSelectedItemsPropertyKey =
DependencyProperty.RegisterReadOnly(
"LastSelectedItems",
typeof (Dictionary<string, int>),
typeof (MemoryCombobox),
new FrameworkPropertyMetadata(default(ObservableCollection<string>), FrameworkPropertyMetadataOptions.None));
public static readonly DependencyProperty LastSelectedItemsProperty = LastSelectedItemsPropertyKey.DependencyProperty;
我现在的问题是:如何在组合框的单个下拉菜单中显示所有项目(标签和两个列表),如下所示:
---------------------
Label: Recently Selected
---------------------
<All items from the 'LastSelectedItems' DependencyProperty>
---------------------
Label: All Items
---------------------
<All items from the 'ItemsSource' property of the combobox
---------------------
我不想为此使用分组,因为这些项将不会在最近使用过的项下面的“所有项”列表中重复出现,就像用户希望的那样。
答案 0 :(得分:1)
您是否尝试过以下方法。它使用分组,但是以特殊方式进行分组,因此不会从总列表/组中删除mru-items:
XAML:
<ComboBox Name="MyCombo" SelectionChanged="MyCombo_SelectionChanged" VerticalAlignment="Top">
<ComboBox.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" Background="DarkGray" Foreground="White" FontWeight="Bold" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ComboBox.GroupStyle>
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" Margin="0,0,5,0" />
<TextBlock Text="{Binding Value}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
后面的代码:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
m_preventFeedback = true;
ItemsList = new ObservableCollection<VMItem>
{
new VMItem(new Item("John", 1234), 2),
new VMItem(new Item("Peter", 2345), 2),
new VMItem(new Item("Michael", 3456), 2),
};
ListCollectionView view = new ListCollectionView(ItemsList);
view.GroupDescriptions.Add(new PropertyGroupDescription("CategoryId", new ItemGroupValueConverter()));
MyCombo.ItemsSource = view;
m_preventFeedback = false;
}
private ObservableCollection<VMItem> ItemsList = new ObservableCollection<VMItem>();
bool m_preventFeedback = false;
private void MyCombo_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (m_preventFeedback) return;
if (MyCombo.SelectedItem is VMItem item)
{
m_preventFeedback = true;
VMItem mru = ItemsList.FirstOrDefault(i => i.Name == item.Name && i.CategoryId == 1) ?? new VMItem(item.Item, 1);
ItemsList.Remove(mru);
ItemsList.Insert(0, mru);
MyCombo.SelectedItem = mru;
m_preventFeedback = false;
}
}
}
public class ItemGroupValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
switch ((int)value)
{
case 1: return "Last Used";
case 2: return "Available Items";
}
return "N/A";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
}
public class VMItem : INotifyPropertyChanged
{
private Item m_item;
public VMItem(Item item, int categoryId)
{
m_item = item;
m_categoryId = categoryId;
}
public string Name
{
get { return m_item.Name; }
set
{
m_item.Name = value;
OnPropertyChanged("Name");
}
}
public int Value
{
get { return m_item.Value; }
set
{
m_item.Value = value;
OnPropertyChanged("Value");
}
}
private int m_categoryId;
public int CategoryId
{
get { return m_categoryId; }
set
{
m_categoryId = value;
OnPropertyChanged("CategoryId");
}
}
public Item Item => m_item;
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string property)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
}
public class Item
{
public Item(string name, int value)
{
Name = name;
Value = value;
}
public string Name { get; set; }
public int Value { get; set; }
}