展开时重绘组合框项目

时间:2009-07-24 14:32:41

标签: .net windows combobox ownerdrawn

我有一个带有绑定组合框的.net 3.5 windows应用程序。我已经覆盖了DrawItem事件,以根据特定条件为各个项目的背景着色。我运行异步线程来更新条件值并调用Invalidate()以重新组合组合框。

这一切都很有效,除了扩展组合框时 - 只为在列表中突出显示的项目调用DrawItem。其他项仅在用户执行某些操作时刷新,例如鼠标悬停在列表中的其他项上或单击其他控件。我想在列表打开时自动重绘其他项目。我该如何实现这一目标?有可能吗?

感谢

编辑:我确定在扩展列表中突出显示的任何项目都会在主组合框显示中重新绘制。列表中的任何项目都不会在控件的展开部分重新绘制。

编辑:这是一个精简的示例表单。对于任何想要测试的人,你应该能够创建一个新的Windows窗体应用程序并将其添加到一个新的类文件中,它应该构建。

要重现该行为,请单击“检测”按钮,然后打开组合框并将鼠标悬停在COM1上。测试结果将以1,3,2的顺序完成。你可以看到,当组合框打开时,COM3会保持黄色,直到你将亮点移到它上面然后关闭。

using System;
using System.Windows.Forms;
using System.Collections.Generic;
using System.IO.Ports;
using System.Diagnostics;
using System.Drawing;

namespace combocolor
{
public partial class Demo2 : Form
{
private System.ComponentModel.IContainer components = null;
private System.Windows.Forms.Label ComPortLabel;
private System.Windows.Forms.ComboBox ComPortComboBox;
private System.Windows.Forms.ErrorProvider MainErrorProvider;
private System.Windows.Forms.Button autoQueryButton;

delegate PortTestResult TestPortDelegate(string portName);
delegate void UpdateTestResultsDelegate(PortTestResult portTestResult);

string[] _ports = new string[] { "COM1", "COM2", "COM3" };
Dictionary<string, int> _autoDetectResults = null;

public Demo2()
{
    InitializeComponent();
}

private void Settings_Load(object sender, EventArgs e)
{
    this.ComPortComboBox.Items.AddRange(this._ports);
    this.ComPortComboBox.SelectedIndex = 0;
}

private void autoQueryButton_Click(object sender, EventArgs e)
{
    // start port testing
    this._autoDetectResults = new Dictionary<string, int>(this._ports.Length);
    foreach (string portName in this._ports)
    {
        this._autoDetectResults.Add(portName, 0);
        this.ComPortComboBox.Invalidate();

        try
        {
            TestPortDelegate testDel = new TestPortDelegate(TestSerialPort);    // check port on a new thread
            testDel.BeginInvoke(portName, new AsyncCallback(TestFinishedCallback), testDel);
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(ex);
        }
    }
}

private void ComPortComboBox_DrawItem(object sender, DrawItemEventArgs e)
{
    SolidBrush backgroundBrush, foregroundBrush;
    Dictionary<int, Color> colormap = new Dictionary<int, Color>();

    colormap.Add(0, Color.Yellow);
    colormap.Add(-1, Color.Red);
    colormap.Add(1, Color.LimeGreen);
    string itemText = (string)ComPortComboBox.Items[e.Index];

    // select a background color based on autodetect status
    if (this._autoDetectResults == null)
    {
        backgroundBrush = new System.Drawing.SolidBrush(e.BackColor);
    }
    else
    {
        int key = this._autoDetectResults[itemText];
        backgroundBrush = new SolidBrush(colormap[key]);
    }

    if ((e.State & DrawItemState.Selected) > 0 && (e.State & DrawItemState.ComboBoxEdit) == 0)
    {
        e.DrawBackground(); // draws the blue highlight
        foregroundBrush = new SolidBrush(e.ForeColor); // text color
    }
    else
    {
        e.Graphics.FillRectangle(backgroundBrush, e.Bounds); // draws the color based on the autodetect results
        foregroundBrush = new SolidBrush(this.ComPortComboBox.ForeColor); // text color 
    }

    e.Graphics.DrawString(itemText, e.Font, foregroundBrush, e.Bounds); // draw the text
}

private PortTestResult TestSerialPort(string portName)
{
    PortTestResult result = new PortTestResult();
    result.PortName = portName;

    // simulated results
    switch (portName)
    {
        case "COM1":
            System.Threading.Thread.Sleep(2000);
            result.UseThisPort = false;
            break;
        case "COM2":
            System.Threading.Thread.Sleep(6000);
            result.UseThisPort = true;
            break;
        case "COM3":
            System.Threading.Thread.Sleep(4000);
            result.UseThisPort = false;
            break;
    }

    return result;
}

private void TestFinishedCallback(IAsyncResult ar)
{
    // get the results from the test function
    TestPortDelegate testPortDelegate = (TestPortDelegate)((System.Runtime.Remoting.Messaging.AsyncResult)ar).AsyncDelegate;
    PortTestResult portTestResult = testPortDelegate.EndInvoke(ar);
    UpdateTestResults(portTestResult); // pass the results along to update the UI
}

private void UpdateTestResults(PortTestResult portTestResult)
{
    if (this.ComPortComboBox.InvokeRequired)
    {
        UpdateTestResultsDelegate updateTestResultsDelegate = new UpdateTestResultsDelegate(UpdateTestResults);
        this.Invoke(updateTestResultsDelegate, portTestResult);
    }
    else
    { // set status based on test result
        if (portTestResult.UseThisPort)
        {
            this._autoDetectResults[portTestResult.PortName] = 1;   // 1 for a good response
            this.ComPortComboBox.SelectedItem = portTestResult.PortName;
        }
        else
        {
            this._autoDetectResults[portTestResult.PortName] = -1; // -1 for a bad response
        }
        this.ComPortComboBox.Invalidate();  // force the combobox to redraw with new colors
    }
}


protected override void Dispose(bool disposing)
{
    if (disposing && (components != null))
    {
        components.Dispose();
    }
    base.Dispose(disposing);
}
private void InitializeComponent()
{
    this.components = new System.ComponentModel.Container();
    this.ComPortComboBox = new System.Windows.Forms.ComboBox();
    this.ComPortLabel = new System.Windows.Forms.Label();
    this.MainErrorProvider = new System.Windows.Forms.ErrorProvider(this.components);
    this.autoQueryButton = new System.Windows.Forms.Button();
    ((System.ComponentModel.ISupportInitialize)(this.MainErrorProvider)).BeginInit();
    this.SuspendLayout();
    this.ComPortComboBox.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed;
    this.ComPortComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
    this.ComPortComboBox.FormattingEnabled = true;
    this.ComPortComboBox.Location = new System.Drawing.Point(71, 12);
    this.ComPortComboBox.Name = "ComPortComboBox";
    this.ComPortComboBox.Size = new System.Drawing.Size(136, 21);
    this.ComPortComboBox.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.ComPortComboBox_DrawItem);
    this.ComPortLabel.Location = new System.Drawing.Point(12, 15);
    this.ComPortLabel.Name = "ComPortLabel";
    this.ComPortLabel.Size = new System.Drawing.Size(53, 13);
    this.ComPortLabel.Text = "&Com Port:";
    this.autoQueryButton.Location = new System.Drawing.Point(213, 11);
    this.autoQueryButton.Name = "autoQueryButton";
    this.autoQueryButton.Size = new System.Drawing.Size(49, 21);
    this.autoQueryButton.Text = "detect";
    this.autoQueryButton.UseVisualStyleBackColor = false;
    this.autoQueryButton.Click += new System.EventHandler(this.autoQueryButton_Click);
    this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
    this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
    this.ClientSize = new System.Drawing.Size(282, 47);
    this.Controls.Add(this.autoQueryButton);
    this.Controls.Add(this.ComPortLabel);
    this.Controls.Add(this.ComPortComboBox);
    this.Name = "Demo";
    this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
    this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
    this.Load += new System.EventHandler(this.Settings_Load);
    ((System.ComponentModel.ISupportInitialize)(this.MainErrorProvider)).EndInit();
    this.ResumeLayout(false);
    this.PerformLayout();
}
}

public class PortTestResult
{
    public string PortName { get; set; }
    public bool UseThisPort { get; set; }
}
}

1 个答案:

答案 0 :(得分:2)

此CodeProject文章提供了有关自定义组合框的重要信息:Article