سؤال

هل وجد أي شخص حلاً مفيدًا لمشكلة DesignMode عند تطوير عناصر التحكم؟

تكمن المشكلة في أنه إذا قمت بدمج عناصر التحكم، فإن DesignMode يعمل فقط للمستوى الأول.سوف يقوم DesignMode للمستويات الثانية والأدنى بإرجاع FALSE دائمًا.

كان الاختراق القياسي هو النظر إلى اسم العملية الجارية وإذا كان "DevEnv.EXE" فيجب أن يكون استوديوًا وبالتالي فإن DesignMode هو TRUE حقًا.

تكمن المشكلة في البحث عن اسم العملية وهو يشق طريقه عبر السجل والأجزاء الغريبة الأخرى، مما يؤدي في النهاية إلى أن المستخدم قد لا يمتلك الحقوق المطلوبة لرؤية اسم العملية.وبالإضافة إلى ذلك فإن هذا الطريق الغريب بطيء جدًا.لذلك كان علينا تجميع المزيد من الاختراقات لاستخدام المفردة، وإذا ظهر خطأ عند السؤال عن اسم العملية، فافترض أن DesignMode هو FALSE.

توجد طريقة جيدة ونظيفة لتحديد DesignMode.سيكون الحصول على Microsoft لإصلاحها داخليًا في إطار العمل أفضل!

هل كانت مفيدة؟

المحلول

بإعادة النظر في هذا السؤال، اكتشفت الآن 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)،
  • التحكم الفرعي (dll)
  • التحكم الفرعي (dll)

ثم قمت بتضمين SubSubControl في SubControl، ثم واحدًا من كل منهما في TestApp.Form.

تعرض لقطة الشاشة هذه النتيجة عند التشغيل.Screenshot of running

تعرض لقطة الشاشة هذه النتيجة مع فتح النموذج في Visual Studio:

Screenshot of not running

خاتمة:يبدو أن دون انعكاس الوحيد الذي يمكن الاعتماد عليه داخل المنشئ هو LicenseUsage، وهو الوحيد الذي يمكن الاعتماد عليه الخارج المنشئ هو "IsDesignedHosted" (بواسطة بلو راجا أقل)

ملاحظة:راجع تعليق ToolmakerSteve أدناه (الذي لم أختبره):"لاحظ أن IsDesignerHosted تم تحديث الإجابة لتشمل LicenseUsage...، لذا يمكن أن يكون الاختبار الآن ببساطة إذا (IsDesignerHosted).النهج البديل هو اختبار LicenseManager في المنشئ وتخزين النتيجة مؤقتًا."

نصائح أخرى

من هذه الصفحة:

([تحرير 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;
    }
}

لقد قدمت تقرير الشوائب مع مايكروسوفت؛أشك في أنه سيذهب إلى أي مكان، ولكن قم بالتصويت عليه على أي حال، حيث من الواضح أن هذا خطأ (سواء كان ذلك أم لا) "من تصمبم").

لماذا لا تقوم بالتحقق من LicenseManager.UsageMode.يمكن أن تحتوي هذه الخاصية على القيم LicenseUsageMode.Runtime أو LicenseUsageMode.Designtime.

إذا كنت تريد تشغيل التعليمات البرمجية فقط في وقت التشغيل، فاستخدم الكود التالي:

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

هذه هي الطريقة التي أستخدمها داخل النماذج:

    /// <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 رد.لا يحسب هذا الحل النتيجة في كل مرة ولكن فقط في المرة الأولى (لا يمكن للكائن تغيير وضع الاستخدام من التصميم إلى وقت التشغيل)

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 هي ملكية خاصة (حسب ما أستطيع قوله).الجواب هو توفير خاصية عامة تكشف عن خاصية DesignMode.وبعد ذلك، يمكنك إجراء نسخ احتياطي لسلسلة عناصر تحكم المستخدم حتى تواجه عنصر تحكم غير مستخدم أو عنصر تحكم في وضع التصميم.شيء من هذا القبيل....

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

     return DesignMode;
  }

حيث ترث كافة عناصر تحكم المستخدم الخاصة بك من MyBaseUserControl.وبدلاً من ذلك، يمكنك تنفيذ واجهة تعرض "RealDeisgnMode".

يرجى ملاحظة أن هذا الرمز ليس رمزًا مباشرًا، بل مجرد تأملات.:)

لم أكن أدرك أنه لا يمكنك الاتصال بـ 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;
}

اضطررت إلى محاربة هذه المشكلة مؤخرًا في Visual Studio 2017 عند استخدام UserControls المتداخلة.لقد قمت بدمج العديد من الأساليب المذكورة أعلاه وفي أماكن أخرى، ثم قمت بتعديل الكود حتى حصلت على طريقة تمديد مناسبة تعمل بشكل مقبول حتى الآن.فهو ينفذ سلسلة من الاختبارات، ويخزن النتيجة في متغيرات منطقية ثابتة بحيث يتم تنفيذ كل فحص مرة واحدة فقط على الأكثر في وقت التشغيل.قد تكون العملية مبالغة، لكنها تمنع تنفيذ التعليمات البرمجية في الاستوديو.أمل أن هذا يساعد شخصاما.

  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;
  }
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top