İç içe geçmiş Denetimlerle DesignMode


87

Kontrolleri geliştirirken DesignMode problemine faydalı bir çözüm bulan var mı?

Sorun şu ki, denetimleri iç içe yerleştirirseniz DesignMode yalnızca ilk seviye için çalışır. İkinci ve daha düşük seviyeler DesignMode her zaman YANLIŞ döndürür.

Standart hack, çalışan sürecin adına bakmaktı ve eğer bu "DevEnv.EXE" ise, o zaman stüdyo olmalı, bu nedenle DesignMode gerçekten DOĞRU.

Bununla ilgili sorun, ProcessName'in aranması, kayıt defterinde ve diğer garip kısımlarda yoluna devam eder ve sonuçta kullanıcının işlem adını görmek için gerekli haklara sahip olmayabileceği sonucuna varılır. Ayrıca bu garip rota çok yavaş. Bu nedenle, bir singleton kullanmak için ek hackler biriktirmek zorunda kaldık ve eğer süreç adı sorulduğunda bir hata atılırsa DesignMode'un FALSE olduğunu varsayalım.

Tasarım Modunu belirlemenin güzel ve temiz bir yolu sırayla. Aslında Microsoft'un dahili olarak çerçeveye düzeltmesini sağlamak daha da iyi olurdu!



8
"Microsoft'un bunu çerçevede dahili olarak düzeltmesini sağlamak" için +1 daha iyi olacaktır - birinin zamanından on dakika, onbinlerce insanın saatlerini kurtarabilir. Bir hataya dayanan bir program ve ondan rahatsız olan 100.000 varsa, bir programı rahatsız etmekten kaçınmak için hatayı saklamanın bir anlamı yoktur!
BlueRaja - Danny Pflughoeft

Merhaba, bu 2008'de gönderildi. Bu şimdi düzeltildi mi?
Jake

VS 2012'de bu artık aynı kalıyor
Boogier

1
Bir UserControl için özel bir tasarımcı kullanıyorsanız (örneğin, ControlDesigner'dan türetilen bir sınıfla test ettim), o zaman EnableDesignMode (subControl) çağrısının alt kontrolün DesignMode özelliğini çalıştırdığına dikkat edin. Bu, soruna etkili bir çözüm değildir, ancak her zaman kontrolümüzü barındıran konteyneri yazmıyoruz.
Protongun

Yanıtlar:


81

Bu soruyu tekrar gözden geçirerek, şimdi bunu yapmanın 5 farklı yolunu 'keşfettim', bunlar aşağıdaki gibidir:

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

Önerilen üç çözümü denemek ve denemek için, üç projeyle küçük bir test çözümü yarattım:

  • TestApp (winforms uygulaması),
  • Alt Kontrol (dll)
  • SubSubControl (dll)

Daha sonra SubSubControl'ü SubControl'e, ardından her birini TestApp.Form'a yerleştirdim.

Bu ekran görüntüsü, çalışırken sonucu gösterir. Koşu ekran görüntüsü

Bu ekran görüntüsü, Visual Studio'da açık formdaki sonucu gösterir:

Çalışmama ekran görüntüsü

Sonuç: kadar görünür yansıma olmadan güvenilir olan tek dahilinde yapıcı LicenseUsage ve güvenilir tek olan dış (tarafından yapıcısı 'IsDesignedHosted' dir BlueRaja aşağıda)

Not: (ı test etmedim olan) aşağıda bakınız ToolmakerSteve yorumu: "O Not IsDesignerHosted cevap LicenseUsage içerecek şekilde güncellenmiştir ..., şimdi test basitçe olabilir if (IsDesignerHosted) alternatif bir yaklaşımdır. Yapıcısı test LicenseManager ve sonucu önbelleğe alın . "


@Benjol: Ya IsDesignerHosted (aşağıda)? (Ayrıca, tasarım zamanı ve çalışma zamanı değiştirildiğini düşünüyorum, çalışma zamanı sırasında ne dediğini kontrol et)
BlueRaja - Danny Pflughoeft

@BlueRaja, o projeyi hala diskte bir yerde
durmalıyım

1
Ampirik bir deneyle açıklama için +1. @Benjol, Bunu tekrar ziyaret etme şansınız olursa, formun kendisindeki değerler için bir durum ekleyebilirsiniz çünkü çocuk kontrolleri, tasarımcıda fiilen düzenlenen sınıftan farklı şekilde ele alınabilir. (Düzenlenen sınıfın kurucusunun tasarımcıda çalıştırılmayacağına dikkat edin.)
Rob Parker

2
Yani, düşünmeden if(LicenseUseage == LicenseUsageMode.Designtime || IsDesignerHosted)% 100 doğru yaklaşım olur mu?
Scott Chamberlain

1
IsDesignerHosted cevabının eklenecek şekilde güncellendiğini unutmayın LicenseUsage..., bu nedenle artık test basitçe yapılabilir if (IsDesignerHosted). Alternatif bir yaklaşım, yapıcıda LicenseManager'ı test etmek ve sonucu önbelleğe almaktır .
ToolmakerSteve

32

Gönderen bu sayfada :

( [Edit 2013] @hopla tarafından sağlanan yöntem kullanılarak oluşturucularda çalışmak üzere düzenlendi)

/// <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 ile bir hata raporu gönderdim ; Herhangi bir yere gideceğinden şüpheliyim, ama yine de oylayın, çünkü bu açıkça bir hata ( "tasarım gereği" olsun veya olmasın ).


29

Neden LicenseManager.UsageMode'u kontrol etmiyorsunuz. Bu özellik, LicenseUsageMode.Runtime veya LicenseUsageMode.Designtime değerlerine sahip olabilir.

Kodun yalnızca çalışma zamanında çalışmasını mı istiyorsunuz, aşağıdaki kodu kullanın:

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

8
+1 Bunu da kullandım. İnsanları ayağa kaldıran şey, DesignMode'un bir yapıcıda çalışmayacağıdır.
Nicholas Piasecki

1
@Nicholas: Çocuk kontrollerinde de çalışmıyor. Basitçe kırıldı.
BlueRaja - Danny Pflughoeft

+1 - türetilmiş bir kontrolün tasarımı sırasında inşa edilen temel kontroller üzerinde de çalışır.
mcw

7

Formların içinde kullandığım yöntem bu:

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

Bu şekilde, DesignMode veya LicenseManager özelliklerinden biri başarısız olsa bile sonuç doğru olacaktır.


1
Evet, bu dediğiniz gibi formlarda çalışacaktır. Ancak torun kullanıcı kontrollerinde yapıcının dışında çalışmadığını belirtmek isterim.
Anlo

5

LicenseManager yöntemini kullanıyorum, ancak örneğin ömrü boyunca kullanım için yapıcıdan değeri önbelleğe alıyorum.

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

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

VB versiyonu:

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

1
Jonathan, cevabına (test edilmiş) bir VB versiyonu ekledim.
ToolmakerSteve

3

Bu kodu başarıyla kullanıyoruz:

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

Önerim, @ blueraja-danny-pflughoeft yanıtının bir optimizasyonu . Bu çözüm sonucu her seferinde değil, yalnızca ilk seferde hesaplar (bir nesne Kullanım Modunu tasarımdan çalışma zamanına değiştiremez)

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

Bir değeri önbelleğe alacaksanız, bu karmaşıklığa gitmeniz için hiçbir neden yoktur. Bunun yerine, sonucu önbelleğe alarak yapıcıdaki basit LicenseManager testini kullanan Jonathan'ın cevabını kullanın .
ToolmakerSteve

Bence bu yöntemin faydası, bazı durumlarda mülke asla ihtiyaç duyulmuyorsa, LicenserManager testine hiç ihtiyaç duymamasıdır.
Sebastian Werk

2

Ben kendim hiç buna yakalanmadım, ancak DesignMode'un sizin üstünüzde herhangi bir yere ayarlanıp ayarlanmadığını görmek için kontrolün Üst zincirinden yukarı yürüyemez miydiniz?


2

Yöntemlerin hiçbiri güvenilir (DesignMode, LicenseManager) veya verimli (İşlem, özyinelemeli kontroller) olmadığından public static bool Runtime { get; private set }, program düzeyinde bir kullanıyorum ve bunu açıkça Main () yönteminin içine ayarlıyorum.


1

DesignMode özel bir özelliktir (anlayabildiğim kadarıyla). Cevap, DesignMode prop'unu ortaya çıkaran bir genel özellik sağlamaktır. Daha sonra, kullanıcı olmayan bir denetimle veya tasarım modunda olan bir denetimle karşılaşana kadar kullanıcı denetimleri zincirini yedekleyebilirsiniz. Bunun gibi bir şey ...

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

     return DesignMode;
  }

Tüm UserControl'lerinizin MyBaseUserControl'den miras aldığı yer. Alternatif olarak, "RealDeisgnMode" u ortaya çıkaran bir arabirim uygulayabilirsiniz.

Lütfen bu kodun canlı kod olmadığını, sadece manşet düşünceleri dışında olduğunu unutmayın. :)


1

Parent.DesignMode'u arayamayacağınızı fark etmemiştim (ve C # 'da' korumalı 'hakkında da bir şeyler öğrendim ...)

İşte yansıtıcı bir sürüm: (designModeProperty'yi statik bir alan haline getirmenin bir performans avantajı olabileceğinden şüpheleniyorum)

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

0

İç içe geçmiş UserControls kullanırken son zamanlarda Visual Studio 2017'de bu sorunla mücadele etmem gerekti. Yukarıda ve başka yerlerde belirtilen yaklaşımların birkaçını birleştirdim, sonra şimdiye kadar kabul edilebilir şekilde çalışan iyi bir uzantı yöntemine sahip olana kadar kodu değiştirdim. Bir dizi kontrol gerçekleştirir ve sonucu statik boole değişkenlerinde depolar, böylece her kontrol çalışma zamanında en fazla yalnızca bir kez gerçekleştirilir. İşlem aşırı olabilir, ancak kodun stüdyoda yürütülmesini engelliyor. Umarım bu birine yardımcı olur.

  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;
  }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.