【问题标题】:Treat control as either ComboBox or TextBox将控件视为 ComboBox 或 TextBox
【发布时间】:2013-04-24 01:30:57
【问题描述】:

解决以下问题的最佳方法是什么?

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*-proprties(这两个控件也有共同点)。

感谢您的想法!

【问题讨论】:

  • Text 属性是您唯一追求的东西吗?
  • 不,这是一个更笼统的问题。这只是一个最小化的例子。我也在使用 AutoComplete*-properties。 (我现在将这个添加到问题中)
  • 你不需要外层吗?如果 controlCombobox 为 null,则它不是 ComboBox 等。
  • .net 版本是什么?动态关键字可能会有所帮助
  • 您可能希望通过获取 AutoComplete-* 属性来更新您的代码示例 - 尽管您进行了编辑,但许多人将 Text 属性归为您唯一想要的东西:)跨度>

标签: c# .net generics


【解决方案1】:
dynamic currentControl =  control;
string text = currentControl.WhatEver;

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

【讨论】:

  • 这很好用,似乎是我最喜欢的解决方案。谢谢。
  • 我认为你不应该在这种情况下使用 dynamic 关键字 - see this question
  • 投反对票,因为@PhilippM 是对的。在这里使用动态很容易出错,并且有更好的方法来解决这个问题。
【解决方案2】:

使用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. 的解决方案。无论如何,非常感谢!
  • @TheWavelength 你需要考虑异常管理,这段代码更容易维护,因为我们知道属性是否存在。使用动态,它在运行时获取属性,除非您将其包装在 try catch 中,否则无法检查。这样做的开销真的没有那么多:)
  • @TheWavelength 如果你正在努力理解这一点,我可以进一步解释:)
  • 嗯,你是对的。使用您的解决方案甚至“更快”(输入代码的意思),因为我可能会错过 try-catch-block。谢谢!不需要解释,我想我明白了;)
【解决方案3】:

取决于您要达到的目标。如果您只是对 text 属性感兴趣,那么它实际上是从 Control 类继承的 - 因此您不需要强制转换对象。所以你只需要:

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

    ...
}

但是,如果您需要更复杂的逻辑,则应考虑重新考虑您的控制流。我建议使用 View / 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
}

希望对你有所帮助!

【讨论】:

  • Control.Text 仅存在于 winforms 库中。这实际上是一个设计缺陷,因为并非所有控件都具有有意义的Text 属性。 System.Windows.Controls.Control(WPF 版本)没有这个公共属性。
猜你喜欢
  • 1970-01-01
  • 2018-05-24
  • 1970-01-01
  • 2011-05-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-09
  • 2019-07-23
相关资源
最近更新 更多