перерисовывать элементы поля со списком при раскрытии

У меня есть приложение Windows .net 3.5 с привязанным комбинированным списком. Я переопределил событие DrawItem, чтобы раскрасить фон отдельных элементов в зависимости от определенных условий. У меня работают асинхронные потоки, которые обновляют значения условий и вызывают Invalidate (), чтобы перерисовать поле со списком.

Все это работает очень хорошо, за исключением случаев, когда поле со списком раскрывается - DrawItem вызывается только для элемента, выделенного в списке. Другие элементы обновляются только тогда, когда пользователь что-то делает, например, наводит курсор на другой элемент в списке или щелкает другой элемент управления. Я хочу, чтобы остальные элементы перерисовывались автоматически, пока список открыт. Как мне этого добиться? Является ли это возможным?

Благодарность

изменить: я определил, что любой элемент, выделенный в расширенном списке, перерисовывается в основном отображении поля со списком. никакие элементы в списке не перерисовываются в развернутой части элемента управления.

изменить: вот урезанный пример формы. для всех, кто хочет протестировать, вы должны иметь возможность создать новое приложение Windows Forms и добавить его в новый файл класса, и оно должно быть построено.

чтобы воспроизвести поведение, нажмите кнопку «обнаружить», затем откройте поле со списком и наведите указатель мыши на 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; }
}
}

person lincolnk    schedule 24.07.2009    source источник


Ответы (1)


В этой статье CodeProject есть отличная информация о настройке поля со списком: Статья

person Stewbob    schedule 24.07.2009