Найдите ErrorProvider в форме Windows во время выполнения - PullRequest
1 голос
/ 11 января 2012

Я делаю библиотеку методов расширения для использования в приложениях форм Windows. Один из методов, которые я собираюсь создать, упростит настройку состояний ошибок на элементах управления вводом, например,

public static void SetError(this System.Windows.Forms.TextBox textBox, string errorMessage)
{
    if (string.IsNullOrEmpty(errorMessage))
    {
        //reset control state
        textBox.BackColor = System.Drawing.SystemColors.WindowText;
    }
    else
    {
        //set background colour to a nice shade of red
        textBox.BackColor = System.Drawing.Color.MistyRose;
    }

    //try to locate an ErrorProvider on the control's containing form.
    var errorProvider = LocateErrorProvider(textBox);

    if (errorProvider != null)
    {
        //set error message on error provider (or clear it)
        errorProvider.SetError(textBox, errorMessage);
    }
}

Я пытаюсь выяснить метод LocateErrorProvider. Я хотел бы проверить, существует ли в моей форме ErrorProvider, а затем использовать его, только если он существует.

ErrorProvider является Component, а не Control, поэтому я не могу добраться до него через свойство form.Controls. Я пытался преобразовать родительскую форму во множество объектов, но безрезультатно.

ОБНОВЛЕНИЕ : мне удалось добраться до ErrorProvider с помощью отражения, используя следующий код:

private static System.Windows.Forms.ErrorProvider GetErrorProvider(System.Windows.Forms.Control control)
{
    //get the containing form of the control
    var form = control.GetContainerControl();

    //use reflection to get to "components" field
    var componentField = form.GetType().GetField("components", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);

    if (componentField != null)
    {
        //get the component collection from field
        var components = componentField.GetValue(form);

        //locate the ErrorProvider within the collection
        return (components as System.ComponentModel.IContainer).Components.OfType<System.Windows.Forms.ErrorProvider>().FirstOrDefault();
    }
    else
    {
        return null;
    }
}

Лично я не слишком люблю использовать жестко закодированное имя поля, чтобы добраться до поля. Но в этом случае все работает нормально. У кого-нибудь есть лучший способ достичь таких же результатов?

Ответы [ 3 ]

3 голосов
/ 12 января 2012

Пока что это, похоже, решает мою проблему:

private static System.Windows.Forms.ErrorProvider GetErrorProvider(System.Windows.Forms.Control control)
{
    //get the containing form of the control
    var form = control.GetContainerControl();

    //use reflection to get to "components" field
    var componentField = form.GetType().GetField("components", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);

    if (componentField != null)
    {
        //get the component collection from field
        var components = componentField.GetValue(form);

        //locate the ErrorProvider within the collection
        return (components as System.ComponentModel.IContainer).Components.OfType<System.Windows.Forms.ErrorProvider>().FirstOrDefault();
    }
    else
    {
        return null;
    }
}

Спасибо Hans & Cody за их прекрасные идеи.

1 голос
/ 11 января 2012

Это то, для чего предназначены интерфейсы. Они применяют класс для реализации поведения. Здесь вы хотите, чтобы форма имела ErrorProvider. Поэтому напишите такой интерфейс:

public interface IHasErrorProvider {
    ErrorProvider Provider { get; }
}

И формы с провайдером ошибок реализуют интерфейс:

public partial class Form1 : Form, IHasErrorProvider {
    public ErrorProvider Provider {
        get { return errorProvider1; }
    }
    // etc..
}

Получение поставщика ошибок теперь просто:

    private static ErrorProvider GetErrorProvider(Control control) {
        var impl = control.FindForm() as IHasErrorProvider;
        return impl != null ? impl.Provider : null;
    }
0 голосов
/ 03 декабря 2013

в VS2005 это работает:

    private static System.Windows.Forms.ErrorProvider GetErrorProvider(System.Windows.Forms.Control control)
    {
        try
        {
            //get the containing form of the control
            System.Windows.Forms.IContainerControl form = control.GetContainerControl();

            //use reflection to get to "components" field
            System.Reflection.FieldInfo componentField = form.GetType().GetField("components", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);

            if (componentField != null)
            {
                //get the component collection from field
                object components = componentField.GetValue(form);
                object oReturn = null;
                //locate the ErrorProvider within the collection
                foreach (object o in ((System.ComponentModel.Container)components).Components)
                {
                    if (o.GetType() == typeof(System.Windows.Forms.ErrorProvider))
                    {
                        oReturn = o;
                        break;
                    }
                }
                return (ErrorProvider)oReturn;
            }
        }
        catch 
        {
            return null;
        }
        return null;
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...