1

コンボボックスがバインドされた .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; }
}
}
4

1 に答える 1

2

この CodeProject の記事には、コンボボックスのカスタマイズに関する優れた情報が含まれています

于 2009-07-24T16:11:24.437 に答える