DesignMode с вложенными элементами управления

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

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

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

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

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

11 ответов


возвращаясь к этому вопросу, я теперь "открыл" 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 в нижестоящем, а затем один из каждого в Файла testapp.Форма.

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

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

Screenshot of not running

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

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


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

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

if (LicenseManager.UsageMode == LicenseUsageMode.Runtime)
{
  bla bla bla...
}

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

([Edit 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; я сомневаюсь, что он пойдет куда угодно, но проголосуйте за него в любом случае, так как это, очевидно, ошибка (независимо от того,"дизайн").


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

    /// <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 завершится ошибкой.


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

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";
  }
}

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

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;
        }
    }
}

Я использую метод 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

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


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


DesignMode является частной собственностью (из того, что я могу сказать). Ответ заключается в предоставлении публичного свойства, которое предоставляет prop DesignMode. Затем можно создать каскадную резервную копию цепочки пользовательских элементов управления до тех пор, пока не появится элемент управления, не являющийся пользователем, или элемент управления, находящийся в режиме конструктора. Что-то вроде этого....

  public bool RealDesignMode()
  {
     if (Parent is MyBaseUserControl)
     {
        return (DesignMode ? true : (MyBaseUserControl) Parent.RealDesignMode;
     }

     return DesignMode;
  }

где все ваши UserControls наследуются от MyBaseUserControl. В качестве альтернативы вы можете реализовать интерфейс, который предоставляет "RealDeisgnMode".

пожалуйста обратите внимание, что этот код не является живым кодом, просто размышления манжеты. :)


Я не понял, что вы не можете назвать родителем.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;
}