DesignMode с вложенными элементами управления - PullRequest
85 голосов
/ 29 августа 2008

Кто-нибудь нашел полезное решение проблемы DesignMode при разработке элементов управления?

Проблема в том, что если вы вкладываете элементы управления, то DesignMode работает только для первого уровня. Второй и нижний уровни DesignMode всегда будут возвращать FALSE.

Стандартным хаком было посмотреть на имя запущенного процесса, и если это "DevEnv.EXE", то он должен быть студийным, поэтому DesignMode действительно TRUE.

Проблема с поиском ProcessName обходится через реестр и другие странные части, в результате чего пользователь может не иметь необходимых прав для просмотра имени процесса. Кроме того, этот странный маршрут очень медленный. Таким образом, нам пришлось накапливать дополнительные хаки, чтобы использовать одиночный код, и если при запросе имени процесса выдается ошибка, тогда предположим, что DesignMode равен FALSE.

Хороший чистый способ определения DesignMode в порядке. Если бы Microsoft исправила это внутренне для фреймворка, было бы еще лучше!

Ответы [ 12 ]

76 голосов
/ 02 апреля 2009

Возвращаясь к этому вопросу, я теперь «открыл» 5 различных способов сделать это, а именно:

System.ComponentModel.DesignMode property

System.ComponentModel.LicenseManager.UsageMode property

private string ServiceString()
{
    if (GetService(typeof(System.ComponentModel.Design.IDesignerHost)) != null) 
        return "Present";
    else
        return "Not present";
}

public bool IsDesignerHosted
{
    get
    {
        Control ctrl = this;

        while(ctrl != null)
        {
            if((ctrl.Site != null) && ctrl.Site.DesignMode)
                return true;
            ctrl = ctrl.Parent;
        }
        return false;
    }
}
public static bool IsInDesignMode()
{
    return System.Reflection.Assembly.GetExecutingAssembly()
         .Location.Contains("VisualStudio"))
}

Чтобы попытаться освоить три предложенных решения, я создал небольшое тестовое решение - с тремя проектами:

  • TestApp (приложение winforms),
  • SubControl (dll)
  • SubSubControl (dll)

Затем я встроил SubSubControl в SubControl, затем по одному в TestApp.Form.

Этот снимок экрана показывает результат при запуске. Screenshot of running

Этот снимок экрана показывает результат с формой, открытой в Visual Studio:

Screenshot of not running

Вывод: может показаться, что без отражения единственный надежный в пределах конструктор - LicenseUsage, и единственный надежный вне конструктор isDesignedHosted ( BlueRaja ниже)

PS: см. Комментарий ToolmakerSteve ниже (который я не тестировал): «Обратите внимание, что IsDesignerHosted ответ был обновлен и теперь содержит LicenseUsage ..., поэтому теперь тест может быть просто if (IsDesignerHosted) . Альтернативным подходом является тестирование LicenseManager в конструкторе и кеширование результата . "

30 голосов
/ 22 апреля 2010

С этой страницы :

( [Редактировать 2013] Отредактировано для работы в конструкторах, используя метод, предоставленный @hopla)

/// <summary>
/// The DesignMode property does not correctly tell you if
/// you are in design mode.  IsDesignerHosted is a corrected
/// version of that property.
/// (see https://connect.microsoft.com/VisualStudio/feedback/details/553305
/// and http://stackoverflow.com/a/2693338/238419 )
/// </summary>
public bool IsDesignerHosted
{
    get
    {
        if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
            return true;

        Control ctrl = this;
        while (ctrl != null)
        {
            if ((ctrl.Site != null) && ctrl.Site.DesignMode)
                return true;
            ctrl = ctrl.Parent;
        }
        return false;
    }
}

Я отправил отчет об ошибке в Microsoft; Я сомневаюсь, что это куда-то пойдет, но все равно проголосуйте, так как это, очевидно, ошибка (неважно, «» «по замыслу» ).

29 голосов
/ 07 декабря 2008

Почему бы вам не проверить LicenseManager.UsageMode. Это свойство может иметь значения LicenseUsageMode.Runtime или LicenseUsageMode.Designtime.

Если вы хотите, чтобы код выполнялся только во время выполнения, используйте следующий код:

if (LicenseManager.UsageMode == LicenseUsageMode.Runtime)
{
  bla bla bla...
}
7 голосов
/ 29 сентября 2010

Это метод, который я использую внутри форм:

    /// <summary>
    /// Gets a value indicating whether this instance is in design mode.
    /// </summary>
    /// <value>
    ///     <c>true</c> if this instance is in design mode; otherwise, <c>false</c>.
    /// </value>
    protected bool IsDesignMode
    {
        get { return DesignMode || LicenseManager.UsageMode == LicenseUsageMode.Designtime; }
    }

Таким образом, результат будет правильным, даже если произойдет сбой свойств DesignMode или LicenseManager.

3 голосов
/ 27 января 2016

Мое предложение - это оптимизация @ blueraja-danny-pflughoeft reply . Это решение не вычисляет результат каждый раз, а только в первый раз (объект не может изменить UsageMode от проектирования до времени выполнения)

private bool? m_IsDesignerHosted = null; //contains information about design mode state
/// <summary>
/// The DesignMode property does not correctly tell you if
/// you are in design mode.  IsDesignerHosted is a corrected
/// version of that property.
/// (see https://connect.microsoft.com/VisualStudio/feedback/details/553305
/// and https://stackoverflow.com/a/2693338/238419 )
/// </summary>
[Browsable(false)]
public bool IsDesignerHosted
{
    get
    {
        if (m_IsDesignerHosted.HasValue)
            return m_IsDesignerHosted.Value;
        else
        {
            if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
            {
                m_IsDesignerHosted = true;
                return true;
            }
            Control ctrl = this;
            while (ctrl != null)
            {
                if ((ctrl.Site != null) && ctrl.Site.DesignMode)
                {
                    m_IsDesignerHosted = true;
                    return true;
                }
                ctrl = ctrl.Parent;
            }
            m_IsDesignerHosted = false;
            return false;
        }
    }
}
3 голосов
/ 21 сентября 2012

Мы успешно используем этот код:

public static bool IsRealDesignerMode(this Control c)
{
  if (System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime)
    return true;
  else
  {
    Control ctrl = c;

    while (ctrl != null)
    {
      if (ctrl.Site != null && ctrl.Site.DesignMode)
        return true;
      ctrl = ctrl.Parent;
    }

    return System.Diagnostics.Process.GetCurrentProcess().ProcessName == "devenv";
  }
}
3 голосов
/ 17 мая 2010

Я использую метод LicenseManager, но кэширую значение из конструктора для использования в течение всего времени существования экземпляра.

public MyUserControl()
{
    InitializeComponent();
    m_IsInDesignMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);
}

private bool m_IsInDesignMode = true;
public bool IsInDesignMode { get { return m_IsInDesignMode; } }

VB версия:

Sub New()
    InitializeComponent()

    m_IsInDesignMode = (LicenseManager.UsageMode = LicenseUsageMode.Designtime)
End Sub

Private ReadOnly m_IsInDesignMode As Boolean = True
Public ReadOnly Property IsInDesignMode As Boolean
    Get
        Return m_IsInDesignMode
    End Get
End Property
2 голосов
/ 02 сентября 2011

Поскольку ни один из методов не является надежным (DesignMode, LicenseManager) или эффективным (Обработка, рекурсивные проверки), я использую public static bool Runtime { get; private set } на уровне программы и явно устанавливаю его внутри метода Main ().

2 голосов
/ 29 августа 2008

Я никогда не был пойман этим самим, но не могли бы вы просто пройтись по родительской цепочке от элемента управления, чтобы увидеть, установлен ли DesignMode где-нибудь над вами?

1 голос
/ 29 августа 2008

Я не понял, что вы не можете вызвать Parent.DesignMode (и я тоже кое-что узнал о «защищенном» в C # ...)

Вот рефлексивная версия: (я подозреваю, что при создании designModeProperty в качестве статического поля может быть преимущество в производительности)

static bool IsDesignMode(Control control)
{
    PropertyInfo designModeProperty = typeof(Component).
      GetProperty("DesignMode", BindingFlags.Instance | BindingFlags.NonPublic);

    while (designModeProperty != null && control != null)
    {
        if((bool)designModeProperty.GetValue(control, null))
        {
            return true;
        }
        control = control.Parent;
    }
    return false;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...