展开时重绘组合框项目
我有一个带有绑定组合框的 .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; }
}
}
I have a .net 3.5 windows application with a bound combobox. I have overridden the DrawItem event to color the background of individual items based on certain conditions. I have asynchronous threads running which update the condition values and call Invalidate() to get the combobox to redraw.
This all works very well, except when the combobox is expanded - DrawItem is only called for the item that's highlighted in the list. The other items only refresh when the user does something, like mouse over another item in the list or click a different control. I would like the other items to redraw automatically while the list is open. How do I make this happen? Is it possible?
thanks
edit: I determined that whatever item is highlighted in the expanded list is redrawn in the main combobox display. no items in the list are redrawn in the expanded part of the control.
edit: here's a stripped down example form. for anyone who wants to test you should be able to create a new windows forms app and add this in a new class file and it should build.
to reproduce the behavior, click the "detect" button, then open the combobox and hover over COM1. test results will finish in the order of 1,3,2. you can see that while the combobox is open, COM3 stays yellow until you move the highlight over it and then off.
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; }
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这篇 CodeProject 文章提供了有关自定义组合框的大量信息:文章
This CodeProject article has great information on customizing the combobox: Article