문제

컨트롤을 개발할 때 DesignMode 문제에 대한 유용한 솔루션을 찾은 사람이 있습니까?

문제는 컨트롤을 중첩하면 DesignMode가 첫 번째 수준에서만 작동한다는 것입니다.두 번째 및 하위 수준 DesignMode는 항상 FALSE를 반환합니다.

표준 해킹은 실행 중인 프로세스의 이름을 확인하는 것이었고 "DevEnv.EXE"라면 studio임에 틀림없으므로 DesignMode는 실제로 TRUE입니다.

ProcessName을 찾는 문제는 레지스트리 및 기타 이상한 부분을 통해 작동하여 최종 결과로 사용자가 프로세스 이름을 보는 데 필요한 권한이 없을 수 있다는 것입니다.게다가 이 이상한 길은 매우 느리다.따라서 우리는 싱글톤을 사용하기 위해 추가 핵을 쌓아야 했으며 프로세스 이름을 물을 때 오류가 발생하면 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)

그런 다음 SubControl에 SubSubControl을 포함시킨 다음 TestApp.Form에 각각 하나씩 포함시켰습니다.

이 스크린샷은 실행 시 결과를 보여줍니다.Screenshot of running

이 스크린샷은 Visual Studio에서 열린 양식의 결과를 보여줍니다.

Screenshot of not running

결론:그것은 나타날 것이다 반성하지 않고 믿을 수 있는 유일한 사람 이내에 생성자는 LicenseUsage이며 신뢰할 수 있는 유일한 생성자입니다. 밖의 생성자는 'IsDesignedHosted'입니다(by 블루라자 아래에)

추신:아래 ToolmakerSteve의 의견을 참조하세요(테스트하지는 않음)."참고하세요. IsDesigner호스팅 LicenseUsage...를 포함하도록 답변이 업데이트되었으므로 이제 테스트는 간단하게 if(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의 최적화입니다. 회신하다.이 솔루션은 매번 결과를 계산하지 않고 처음에만 계산합니다(객체는 디자인에서 런타임까지 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;
        }
    }
}

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

모든 UserControl이 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에서 중첩된 UserControl을 사용할 때 이 문제를 해결해야 했습니다.위에서 언급한 여러 접근 방식과 다른 곳에서 언급한 접근 방식을 결합한 다음, 지금까지 수용 가능한 괜찮은 확장 방법을 얻을 때까지 코드를 수정했습니다.일련의 검사를 수행하여 결과를 정적 부울 변수에 저장하므로 각 검사는 런타임에 최대 한 번만 수행됩니다.프로세스가 과도할 수 있지만 이로 인해 스튜디오에서 코드가 실행되지 않습니다.이것이 누군가에게 도움이 되기를 바랍니다.

  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