In a combobox, how do I determine the highlighted

2019-04-08 21:05发布

问题:

First, fair warning: I am a complete newbie with C# and WPF.

I have a combobox (editable, searchable) and I would like to be able to intercept the Delete key and remove the currently highlighted item from the list. The behavior I'm looking for is like that of MS Outlook when entering in email addresses. When you give a few characters, a dropdown list of potential matches is displayed. If you move to one of these (with the arrow keys) and hit Delete, that entry is permanently removed. I want to do that with an entry in the combobox.

Here is the XAML (simplified):


<ComboBox x:Name="Directory"
    KeyUp="Directory_KeyUp"
    IsTextSearchEnabled="True"
    IsEditable="True"
    Text="{Binding Path=CurrentDirectory, Mode=TwoWay}"
    ItemsSource="{Binding Source={x:Static self:Properties.Settings.Default}, 
        Path=DirectoryList, Mode=TwoWay}" />

The handler is:


private void Directory_KeyUp(object sender, KeyEventArgs e)
{
    ComboBox box = sender as ComboBox;
    if (box.IsDropDownOpen &&  (e.Key == Key.Delete))
    {
        TrimCombobox("DirectoryList", box.HighlightedItem);  // won't compile!
    }
}

When using the debugger, I can see box.HighlightedItem has the value I want but when I try and put in that code, it fails to compile with:

System.Windows.Controls.ComboBox' does not contain a definition for 'HighlightedItem'...

So: how do I access that value? Keep in mind that the item has not been selected. It is merely highlighted as the mouse hovers over it.

Thanks for your help.

Here is a screenshot showing the debugger's display. I hovered over "box" and when the one-line summary was displayed, I then hovered over the + char to expand to this image:

alt text http://www.freeimagehosting.net/uploads/2cff35d340.gif

回答1:

The Highlighted Item property is a Non-Public member, so you can't call it from another class.

alt text http://www.freeimagehosting.net/uploads/1e4dc53cee.png

I believe you need to use Reflection to get at Non-Public members. Here's a SO post on the subject: Access non-public members - ReflectionAttribute



回答2:

Below is the final code, as inspired by Jean Azzopardi's answer. The HighlightedItem that was showing up in the debugger was a non-public property and I am forcing access with a sequence of GetType().GetProperty().GetValue()

private void Directory_KeyUp(object sender, KeyEventArgs e)
{
    ComboBox box = sender as ComboBox;
    if (box.IsDropDownOpen && (e.Key == Key.Delete))
    {
        const BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
        PropertyInfo hl = box.GetType().GetProperty("HighlightedItem", flags);
        if (hl != null)
        {
            String hlString = hl.GetValue(sender, null) as String;
            // TODO: remove from DirectoryList
        }
    }
}


回答3:

You can create your own DrawItem Event handler and save the index of the items as they are actively being drawn and keep the DrawItemState.Selected (ie. the highlighted) one.

void Main()
{
    Application.Run(new Form1());
}

public partial class Form1 : Form
{
    ComboBox ComboBox1;
    string[] ds = new string[]{"Foo", "Bar", "Baz"};

    public Form1 ()
    {
        InitializeComboBox();
    }

    private void InitializeComboBox()
    {
        ComboBox1 = new ComboBox();

        ComboBox1.DataSource = ds;
        Controls.Add(ComboBox1);

        ComboBox1.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawVariable;
        ComboBox1.DrawItem += new DrawItemEventHandler(ComboBox1_DrawItem);
    }

    private void ComboBox1_DrawItem(object sender, DrawItemEventArgs e)
    {
        e.DrawBackground();
        e.Graphics.DrawString(ds[e.Index],ComboBox1.Font,Brushes.Black,e.Bounds);

        if (e.State == DrawItemState.Selected)
        {
            //stores the "HighlightedIndex" in the control's tag field.  Change as you see fit.
            ComboBox1.Tag = e.Index; 
            //Console.WriteLine(e.Index);
        }
    }
}


回答4:

The definition of System.Windows.Controls.ComboBox does not contain a property HighlightedItem - that's why you're code does not compile.

Are you using a combo box derived from System.Windows.Controls.ComboBox? Then just cast it to the appropriate type.

Later note: If you want to catch the highlighted event of a ComboBox read this link - it addresses exactly this issue.