Winforms 将 Control 转换为其他控件类型并分配特定的事件处理程序
Winforms cast Control to other control type and assign specific event handler
至于问题,我正在以编程方式创建控件,根据变量,我需要创建不同的控件类型,然后将它们添加到面板中。
当我尝试从 Control 转换 CheckBox 并添加 CheckedChanged
事件时,我得到“Control does not contain a definition for that [...]”。
我知道我可以复制 Panel.Add(Control)
行并避免使用公共控件,但我想知道是否可以从更通用的控件
中正确转换控件
Control val;
if (dataType.Equals(COIL))
{
val = new CheckBox
{
Name = $"txt{i}"
};
val.CheckedChanged += ChangeValue;
}
else
{
val = new TextBox
{
Name = $"txt{i}",
Size = new Size(70, 20),
TextAlign = HorizontalAlignment.Center,
TabIndex = i
};
}
flpValues.Controls.AddRange(new Control[] { lbl, val });
有什么问题?
您有这样的代码:
Control val;
// ...
val = new CheckBox
{
Name = $"txt{i}"
};
val.CheckedChanged += ChangeValue;
它不起作用,因为 Control
中没有 CheckedChanged
,而 val
尽管 CheckBox
被键入为 Control
。
如何解决?
你可以施法:
Control val;
// ...
val = new CheckBox
{
Name = $"txt{i}"
};
((CheckBox)val).CheckedChanged += ChangeValue;
但是,在我看来,那是在做不必要的额外工作。我会改用另一个变量:
Control val;
// ...
var checkBox = new CheckBox
{
Name = $"txt{i}"
};
checkBox.CheckedChanged += ChangeValue;
val = checkBox;
事实上,这可以很容易地将这些行提取到另一个方法中,让您:
Control val;
// ...
val = CreateCheckBox(i);
你能安全投出吗?
或许你更感兴趣的是能不能安全施法。毕竟,当您编写 ((CheckBox)val)
时,编译器不会检查类型是否正确,而是在运行时进行检查(如果失败则抛出,这不会发生)。
有几种安全转换的方法,从 as
:
开始
Control val;
// ...
val = new CheckBox
{
Name = $"txt{i}"
};
(val as CheckBox).CheckedChanged += ChangeValue;
现在,根据您的分析器,您可能会收到警告。由于使用 as
进行转换不会抛出,但可能 return 为 null。这在理论上会导致异常。当然,我们知道这不会发生以防万一(因此您可以抑制任何警告,如果有的话)。
另一种选择是使用 is
:
Control val;
// ...
val = new CheckBox
{
Name = $"txt{i}"
};
if (val is CheckBox checkBox)
{
checkBox.CheckedChanged += ChangeValue;
}
现在我引入了条件语句(我们知道它永远为真)和一个新变量。至少它没有警告。然而,很明显,我最初建议的仅使用附加变量绝对比这更好(因为该解决方案没有条件)。
编译器会优化吗?
可能你担心编译器会不会优化代码
代码 ((CheckBox)val)
will result in a castclass
opcode. (val as CheckBox)
will result in a isinst
opcode. Similarly if (val is CheckBox checkBox)
将导致 isinst
,加上分支(我在 sharplab 中得到 brfalse.s
)。
不是,JIT 编译器似乎也没有优化它。事实上,使用新变量的 the suggested solution 没有任何与转换或检查类型相关的操作码。它也是 JIT asm 中较短的代码。
至于问题,我正在以编程方式创建控件,根据变量,我需要创建不同的控件类型,然后将它们添加到面板中。
当我尝试从 Control 转换 CheckBox 并添加 CheckedChanged
事件时,我得到“Control does not contain a definition for that [...]”。
我知道我可以复制 Panel.Add(Control)
行并避免使用公共控件,但我想知道是否可以从更通用的控件
Control val;
if (dataType.Equals(COIL))
{
val = new CheckBox
{
Name = $"txt{i}"
};
val.CheckedChanged += ChangeValue;
}
else
{
val = new TextBox
{
Name = $"txt{i}",
Size = new Size(70, 20),
TextAlign = HorizontalAlignment.Center,
TabIndex = i
};
}
flpValues.Controls.AddRange(new Control[] { lbl, val });
有什么问题?
您有这样的代码:
Control val;
// ...
val = new CheckBox
{
Name = $"txt{i}"
};
val.CheckedChanged += ChangeValue;
它不起作用,因为 Control
中没有 CheckedChanged
,而 val
尽管 CheckBox
被键入为 Control
。
如何解决?
你可以施法:
Control val;
// ...
val = new CheckBox
{
Name = $"txt{i}"
};
((CheckBox)val).CheckedChanged += ChangeValue;
但是,在我看来,那是在做不必要的额外工作。我会改用另一个变量:
Control val;
// ...
var checkBox = new CheckBox
{
Name = $"txt{i}"
};
checkBox.CheckedChanged += ChangeValue;
val = checkBox;
事实上,这可以很容易地将这些行提取到另一个方法中,让您:
Control val;
// ...
val = CreateCheckBox(i);
你能安全投出吗?
或许你更感兴趣的是能不能安全施法。毕竟,当您编写 ((CheckBox)val)
时,编译器不会检查类型是否正确,而是在运行时进行检查(如果失败则抛出,这不会发生)。
有几种安全转换的方法,从 as
:
Control val;
// ...
val = new CheckBox
{
Name = $"txt{i}"
};
(val as CheckBox).CheckedChanged += ChangeValue;
现在,根据您的分析器,您可能会收到警告。由于使用 as
进行转换不会抛出,但可能 return 为 null。这在理论上会导致异常。当然,我们知道这不会发生以防万一(因此您可以抑制任何警告,如果有的话)。
另一种选择是使用 is
:
Control val;
// ...
val = new CheckBox
{
Name = $"txt{i}"
};
if (val is CheckBox checkBox)
{
checkBox.CheckedChanged += ChangeValue;
}
现在我引入了条件语句(我们知道它永远为真)和一个新变量。至少它没有警告。然而,很明显,我最初建议的仅使用附加变量绝对比这更好(因为该解决方案没有条件)。
编译器会优化吗?
可能你担心编译器会不会优化代码
代码 ((CheckBox)val)
will result in a castclass
opcode. (val as CheckBox)
will result in a isinst
opcode. Similarly if (val is CheckBox checkBox)
将导致 isinst
,加上分支(我在 sharplab 中得到 brfalse.s
)。
不是,JIT 编译器似乎也没有优化它。事实上,使用新变量的 the suggested solution 没有任何与转换或检查类型相关的操作码。它也是 JIT asm 中较短的代码。