Обработать управление как ComboBox или TextBox

Каков наилучший способ решить следующую проблему?

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.

Моя первая идея заключалась в том, чтобы использовать generic с несколькими типами для T, но кажется, что это невозможно в .NET:

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

К сожалению, оба элемента управления не имеют общего базового класса.

Примечание. Это будет более общий вопрос, используемый с минимизированным примером. В моем случае я также хочу получить доступ к другим функциям AutoComplete * -proprties/которые также имеют общие элементы управления.

Спасибо за идеи!

Ответ 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
}

Ответ 2

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

Но он выдает исключение (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException), если currentControl не имеет свойства WhatEver

Ответ 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
}

Я надеюсь, что это поможет!