Frage

Hat jemand eine nützliche Lösung für das DesignMode-Problem bei der Entwicklung von Steuerelementen gefunden?

Das Problem besteht darin, dass DesignMode beim Verschachteln von Steuerelementen nur für die erste Ebene funktioniert.Der DesignMode der zweiten und niedrigeren Ebene gibt immer FALSE zurück.

Der Standard-Hack bestand darin, sich den Namen des laufenden Prozesses anzusehen. Wenn es sich um „DevEnv.EXE“ handelt, muss es Studio sein, sodass DesignMode wirklich WAHR ist.

Das Problem dabei ist, dass sich die Suche nach dem Prozessnamen durch die Registrierung und andere seltsame Teile schlängelt, mit dem Endergebnis, dass der Benutzer möglicherweise nicht über die erforderlichen Rechte verfügt, um den Prozessnamen anzuzeigen.Außerdem ist diese seltsame Route sehr langsam.Wir mussten also zusätzliche Hacks anhäufen, um einen Singleton zu verwenden, und wenn bei der Abfrage des Prozessnamens ein Fehler ausgegeben wird, gehen wir davon aus, dass DesignMode FALSE ist.

Eine schöne, saubere Möglichkeit, DesignMode zu bestimmen, ist in Ordnung.Tatsächlich wäre es sogar noch besser, Microsoft dazu zu bringen, das Problem intern im Framework zu beheben!

War es hilfreich?

Lösung

Bei der erneuten Betrachtung dieser Frage habe ich nun fünf verschiedene Möglichkeiten „entdeckt“, dies zu tun:

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

Um einen Eindruck von den drei Lösungsvorschlägen zu bekommen, habe ich eine kleine Testlösung erstellt – mit drei Projekten:

  • TestApp (Winforms-Anwendung),
  • SubControl (dll)
  • SubSubControl (dll)

Dann habe ich das SubSubControl in das SubControl eingebettet, dann jeweils eines in die TestApp.Form.

Dieser Screenshot zeigt das Ergebnis beim Ausführen.Screenshot of running

Dieser Screenshot zeigt das Ergebnis mit dem in Visual Studio geöffneten Formular:

Screenshot of not running

Abschluss:Es scheint so ohne Reflexion der Einzige, der zuverlässig ist innerhalb Der Konstruktor ist LicenseUsage und der einzige, der zuverlässig ist draußen Der Konstruktor ist „IsDesignedHosted“ (von BlueRaja unten)

PS:Siehe den Kommentar von ToolmakerSteve unten (den ich nicht getestet habe):"Beachten Sie, dass IsDesignerHosted Die Antwort wurde aktualisiert und enthält jetzt LicenseUsage..., sodass der Test jetzt einfach if (IsDesignerHosted) lauten kann.Ein alternativer Ansatz ist Testen Sie LicenseManager im Konstruktor und speichern Sie das Ergebnis zwischen."

Andere Tipps

Aus diese Seite:

([Bearbeiten 2013] Bearbeitet, um in Konstruktoren zu funktionieren, unter Verwendung der von @hopla bereitgestellten Methode)

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

Ich habe eingereicht ein Fehlerbericht mit Microsoft;Ich bezweifle, dass es irgendwohin führt, aber stimmen Sie trotzdem dafür, da es sich offensichtlich um einen Fehler handelt (unabhängig davon, ob es einer ist oder nicht). "von Entwurf").

Warum überprüfen Sie nicht LicenseManager.UsageMode?Diese Eigenschaft kann die Werte LicenseUsageMode.Runtime oder LicenseUsageMode.Designtime haben.

Soll der Code nur zur Laufzeit ausgeführt werden, verwenden Sie den folgenden Code:

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

Dies ist die Methode, die ich in Formularen verwende:

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

Auf diese Weise ist das Ergebnis auch dann korrekt, wenn eine der DesignMode- oder LicenseManager-Eigenschaften fehlschlägt.

Wir verwenden diesen Code mit Erfolg:

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

Mein Vorschlag ist eine Optimierung von @blueraja-danny-pflughoeft Antwort.Diese Lösung berechnet das Ergebnis nicht jedes Mal, sondern nur beim ersten Mal (ein Objekt kann den UsageMode nicht vom Entwurf zur Laufzeit ändern).

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

Ich verwende die Methode „LicenseManager“, speichere den Wert des Konstruktors jedoch zwischen, damit er während der gesamten Lebensdauer der Instanz verwendet werden kann.

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

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

VB-Version:

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

Das hat mich selbst noch nie erwischt, aber könnten Sie nicht einfach vom Steuerelement aus die übergeordnete Kette hinaufgehen, um zu sehen, ob DesignMode irgendwo über Ihnen eingestellt ist?

Da keine der Methoden zuverlässig (DesignMode, LicenseManager) oder effizient (Process, rekursive Prüfungen) ist, verwende ich eine public static bool Runtime { get; private set } auf Programmebene und explizites Festlegen innerhalb der Main()-Methode.

DesignMode ist Privatbesitz (soweit ich das beurteilen kann).Die Antwort besteht darin, eine öffentliche Eigenschaft bereitzustellen, die die DesignMode-Requisite verfügbar macht.Anschließend können Sie die Kette der Benutzersteuerelemente kaskadieren, bis Sie auf ein Nichtbenutzersteuerelement oder ein Steuerelement stoßen, das sich im Entwurfsmodus befindet.Etwas wie das....

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

     return DesignMode;
  }

Wo alle Ihre UserControls von MyBaseUserControl erben.Alternativ könnten Sie eine Schnittstelle implementieren, die den „RealDeisgnMode“ verfügbar macht.

Bitte beachten Sie, dass es sich bei diesem Code nicht um einen Live-Code handelt, sondern nur um spontane Überlegungen.:) :)

Mir war nicht klar, dass man Parent.DesignMode nicht aufrufen kann (und ich habe auch etwas über „geschützt“ in C# gelernt ...)

Hier ist eine reflektierende Version:(Ich vermute, dass es einen Leistungsvorteil geben könnte, designModeProperty zu einem statischen Feld zu machen)

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

Mit diesem Problem hatte ich kürzlich in Visual Studio 2017 zu kämpfen, als ich verschachtelte UserControls verwendete.Ich kombiniere mehrere der oben und anderswo genannten Ansätze und habe dann den Code optimiert, bis ich eine anständige Erweiterungsmethode hatte, die bisher akzeptabel funktioniert.Es führt eine Folge von Prüfungen durch und speichert das Ergebnis in statischen booleschen Variablen, sodass jede Prüfung höchstens einmal zur Laufzeit durchgeführt wird.Der Prozess mag übertrieben sein, aber er verhindert, dass der Code in Studio ausgeführt wird.Hoffe, das hilft jemandem.

  public static class DesignTimeHelper
  {
    private static bool? _isAssemblyVisualStudio;
    private static bool? _isLicenseDesignTime;
    private static bool? _isProcessDevEnv;
    private static bool? _mIsDesignerHosted; 

    /// <summary>
    ///   Property <see cref="Form.DesignMode"/> does not correctly report if a nested <see cref="UserControl"/>
    ///   is in design mode.  InDesignMode is a corrected that property which .
    ///   (see https://connect.microsoft.com/VisualStudio/feedback/details/553305
    ///   and https://stackoverflow.com/a/2693338/238419 )
    /// </summary>
    public static bool InDesignMode(
      this Control userControl,
      string source = null)
      => IsLicenseDesignTime
         || IsProcessDevEnv
         || IsExecutingAssemblyVisualStudio
         || IsDesignerHosted(userControl);

    private static bool IsExecutingAssemblyVisualStudio
      => _isAssemblyVisualStudio
         ?? (_isAssemblyVisualStudio = Assembly
           .GetExecutingAssembly()
           .Location.Contains(value: "VisualStudio"))
         .Value;

    private static bool IsLicenseDesignTime
      => _isLicenseDesignTime
         ?? (_isLicenseDesignTime = LicenseManager.UsageMode == LicenseUsageMode.Designtime)
         .Value;

    private static bool IsDesignerHosted(
      Control control)
    {
      if (_mIsDesignerHosted.HasValue)
        return _mIsDesignerHosted.Value;

      while (control != null)
      {
        if (control.Site?.DesignMode == true)
        {
          _mIsDesignerHosted = true;
          return true;
        }

        control = control.Parent;
      }

      _mIsDesignerHosted = false;
      return false;
    }

    private static bool IsProcessDevEnv
      => _isProcessDevEnv
         ?? (_isProcessDevEnv = Process.GetCurrentProcess()
                                  .ProcessName == "devenv")
         .Value;
  }
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top