将控件视为ComboBox或TextBox

10
什么是解决以下问题的最佳方法?
foreach (Control control in this.Controls)
{
    if (control is ComboBox || control is TextBox)
    {
        ComboBox controlCombobox = control as ComboBox;
        TextBox controlTextbox = control as TextBox;

        AutoCompleteMode value = AutoCompleteMode.None;

        if (controlCombobox != null)
        {
            value = controlCombobox.AutoCompleteMode;
        }
        else if (controlTextbox != null)
        {
            value = controlTextbox.AutoCompleteMode;
        }

        // ...
    }
}

您看,获取AutoCompleteMode属性已经足够复杂了。可以假设我有一个ComboBox或者TextBox。

我的第一个想法是使用多个类型的泛型T,但似乎在.NET中不可能实现:

public string GetAutoCompleteModeProperty<T>(T control) where T: ComboBox, TextBox // this does not work, of course

很遗憾,这两个控件没有共同的基类。

: 这是一个更为通用的问题,使用了一个最小化的示例。在我的情况下,我还希望访问/操作其他AutoComplete*属性(这两个控件也都有相同的属性)。

谢谢您的建议!


你只需要 Text 属性吗? - Tim
不,这是一个更一般的问题。这只是一个最小化的例子。我也在使用AutoComplete*属性。(我现在将其添加到问题中) - The Wavelength
你不需要外层的if语句吧?如果controlCombobox为空,那它就不是一个ComboBox等等。 - MAV
1
什么是 .NET 版本?dynamic 关键字可能会有所帮助。 - Bogdan M.
2
您可能希望更新您的代码示例,同时获取AutoComplete-*属性 - 尽管您进行了编辑,但很多人仍然将Text属性视为您唯一想要的东西 :) - Tim
显示剩余2条评论
3个回答

5
dynamic currentControl =  control;
string text = currentControl.WhatEver;

但是,如果 currentControl 没有 WhatEver 属性,则会引发异常(Microsoft.CSharp.RuntimeBinder.RuntimeBinderException)


这个方案运行良好,似乎是我最喜欢的解决方案。谢谢。 - The Wavelength
5
我认为在这种情况下你不应该使用 dynamic 关键字 - 参见此问题 - Philipp M
因为@PhilippM是正确的,所以被踩了。在这里使用动态语言是容易出错的,有更好的方法可以解决这个问题。 - CodingMadeEasy

1

取决于您想要实现什么。如果您只对文本属性感兴趣,则实际上这是从Control类继承的 - 因此您不需要转换对象。所以您只需要:

foreach (var control in this.Controls)
{
    value = control.Text;

    ...
}

如果您需要更复杂的逻辑,您应该考虑重新思考控制流程。我建议使用视图/Presenter模型,并单独处理每个事件——单一职责的方法可以大大降低复杂性。
如果您为视图分配预期属性的接口——例如view.FirstName、view.HouseName或view.CountrySelection,那么实现(即TextBox、ComboBox等)就会被隐藏。因此:
public interface IMyView
{
    string FirstName { get; }
    string HouseName { get;}
    string CountrySelection { get; }
}

public class MyView : Form, IMyView
{
    public string FirstName { get { return this.FirstName.Text; } } // Textbox
    public string HouseName { get { return this.HouseName.Text; } } // Textbox
    public string CountrySelection { get { return this.CountryList.Text; } // Combobox
}

我希望这对你有所帮助!


1
Control.Text 仅存在于 winforms 库中。实际上,这是一个设计缺陷,因为并非所有控件都具有有意义的 Text 属性。System.Windows.Controls.Control(WPF 版本)没有这个常见属性。 - MartinStettner

1
使用 Type.GetType()。您只需输入属性的 string 表示即可。
if (sender is ComboBox || sender is TextBox)
{
  var type = Type.GetType(sender.GetType().AssemblyQualifiedName, false, true);
  var textValue = type.GetProperty("Text").GetValue(sender, null);
}

这还允许您设置属性的值。
type.GetProperty("Text").SetValue(sender, "This is a test", null);

你可以将这段代码移至辅助方法中,以避免重复编写。
public void SetProperty(Type t, object sender, string property, object value)
{
  t.GetProperty(property).SetValue(sender, value, null);
}
public object GetPropertyValue(Type t, object sender, string property)
{
  t.GetProperty(property).GetValue(sender, null);
}

使用这种方法还可以进行异常处理。
var property = t.GetProperty("AutoCompleteMode");
if (property == null)
{
  //Do whatever you need to do
}

这里似乎有一个不错的解决方案,也可以运作。但在我的情况下,这会带来太大的开销,因为我正在尝试进行快速开发。因此,个人上我更喜欢 Badgan M.的解决方案。无论如何还是非常感谢! - The Wavelength
1
@TheWavelength 你需要考虑异常管理,这段代码更易于维护,因为我们知道属性是否存在。使用动态编程,在运行时获取属性,没有办法进行检查,除非将其包装在 try catch 语句中。实际上,这种开销并不是很大 :) - LukeHennerley
@TheWavelength 如果你对这个的理解有困难,我可以进一步解释 :) - LukeHennerley
好的,你说得对。使用你的解决方案甚至可以更快地(指输入代码)完成,因为我可以省略try-catch块。谢谢!不需要解释,我想我明白了 ;) - The Wavelength

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接