我有一个小问题,已经困扰了我几个小时了。
在我的 WinForms (.NET 3.5) 应用程序中,我在运行时在 TableLayoutPanel 中创建一些组合框 (DropDownStyle = DropDown) 并用字符串填充它。组合框配置为自动调整大小(锚点 = 左 | 右)。
问题是,每当调整组合框的大小(即调整对话框的大小)时,组合框的编辑框部分都会被完全选择/突出显示。在我看来,这会给客户带来非常混乱的效果,我想避免这种情况。
如果 ComboBox 具有固定大小,则不会出现该问题。
另请注意,更改 DropDownStyle 不是一个选项 - 我需要手动输入文本的可能性。
我已经尝试过重写 OnPaint 方法,但这不太有效。 我还尝试清除 ComboBox.Resize 事件中的选择,这在某种程度上起作用,但似乎是一个非常丑陋的解决方案 - 有很多闪烁,故意选择的文本被取消选择,我必须将事件处理程序添加到每个以及对话框中的每个组合框。
这个问题有更好的解决办法吗?
提前谢谢您。
问候, 安迪
这是一个老问题,但我发现它正在寻找答案并最终实现了我自己的解决方案。不妨发在这里吧?
foreach (var cb in Controls.OfType<ComboBox>())
{
cb.Resize += (sender, e) => {
if (!cb.Focused)
cb.SelectionLength = 0;
};
}
故意选择的文本被取消选择
这个 WinForms 错误不会影响选定的组合框,因此通过忽略具有焦点的组合框,我们可以解决丢失当前选择的问题。
我必须添加事件处理程序 到我的每个组合框 对话框。
由 foreach 循环处理。如果您不想破坏设计器,或者让设计器破坏它,请将其放入 InitializeComponent() 或您的 .ctor 中。
有很多闪烁
如果调整大小非常快,我只会看到闪烁,但我使用的是 Win7,所以在 XP 上可能会有所不同。
到目前为止,所有答案都不适合我。我发现的唯一可靠的方法是通过
BeginInvoke
异步发布消息,在控件上的所有其他活动完成后将 SelectionLength
设置回零。闪烁量非常烦人且不专业,但这是迄今为止我能想到的最好的。
internal class FixedComboBox : ComboBox
{
protected override void OnResize(EventArgs e)
{
if (IsHandleCreated && !Focused)
{
BeginInvoke((Action)(() =>
{
SelectionLength = 0;
}));
}
base.OnResize(e);
}
}
帮助我在调用
WM_WINDOWPOSCHANGED
时将选择长度更改为 0。
即使将 tableLayoutPanel 设置为 % 也能正常工作。
protected override void WndProc(ref Message m) {
base.WndProc(ref m);
if(m.Msg == 0x0047) { // WM_WINDOWPOSCHANGED = 0x0047
if (SelectionLength != 0) {
SelectionLength = 0;
}
}
}
哇。谢谢你们!
显然这个错误已经持续了很多年。 我正在使用 .Net 4 (Visual Studio 2010) 构建 UserControl。 这是我对 bsneeze 代码稍作修改的版本。
干杯
using System.Windows.Forms;
using System.Linq;
public MyUserControlCtor()
{
InitializeComponent();
foreach( Control ctrl in Controls)
{
ComboBox cb = ctrl as ComboBox;
if (cb != null)
{
cb.Resize += (sender, e) =>
{
if (!cb.Focused)
this.FCHZ_ComboBox.SelectionLength = 0;
};
}
}
}
处理 ComboBox 父容器的 Resize 事件。把这一行放在那里:
MyComboBox.SelectionLength = 0
一个例子(VB,显然):
Private Sub MyControl_Resize(sender As Object, e As EventArgs) Handles Me.Resize
MyComboBox.SelectionLength = 0
End Sub
祝你好运!
--BP
我发现在组合框所在的任何控件的调整大小事件上将组合框的选择长度设置为 0 会导致很多更少的闪烁,而不是在调整组合本身的大小时执行此操作。
我实际上在 VB.Net 中实现了这一点,但它应该同样适用于 C#。
对于 TableLayoutPanel 内的 ComboBox,在 ComboBox.Resize 事件上设置 .SelectionLength = 0 不起作用,但在 TableLayoutPanel.Resize 事件上执行此操作可以:
Private Sub TableLayoutPanel_Resize(sender As Object, e As EventArgs)
Dim curr_panel = TryCast(sender, System.Windows.Forms.TableLayoutPanel)
For Each curr_combo As ComboBox In curr_panel.Controls.OfType(Of ComboBox)
If ((Not curr_combo.Focused) And curr_combo.DropDownStyle = ComboBoxStyle.DropDown) Then
curr_combo.SelectionLength = 0
End If
Next
End Sub
dim panel as new TableLayoutPanel with {
...
}
AddHandler panel.Resize, AddressOf TableLayoutPanel_Resize
是的,这个仍然存在,并且它并不特定于 TableLayoutPanel 上。 ComboBox 就是这样做的。
无论您在堆栈中的哪个点插入对这种不良行为的更正,我发现通常建议的更正是让它继续并选择全部,然后快速设置 SelectionLength = 0。
这仍然是一个非常明显的闪光,突出显示所有文本,然后取消突出显示它。我可以建议使用一种温和到你甚至看不到的闪光灯吗? 删除文本,让 ComboBox 执行其操作,无需选择任何内容,然后将文本放回去。它会像这样......
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_COMMAND)
{
if (m.WParam.ToInt32() >> 16 == EN_SETFOCUS)
{
// Unnecessary Select All #1: it wants to select all whenever you click on it.
// Solution: Remove all text. Checkmate.
_resizing = true;
string temp = Text;
Text = "";
base.WndProc(ref m);
Text = temp;
_resizing = false;
return;
}
}
else if (m.Msg == WM_SIZE)
{
// Unnecessary Select All #2: it wants to select all whenever you resize.
// Solution: Remove all text again.
_resizing = true;
string temp = Text;
Text = "";
base.WndProc(ref m);
Text = temp;
_resizing = false;
return;
}
base.WndProc(ref m);
}
protected override void OnTextChanged(EventArgs e)
{
if (!_resizing) base.OnTextChanged(e);
}