การตรวจจับโหมดการออกแบบจากตัวสร้างการควบคุม


101

คำถามที่ตามมาจากคำถามนี้เป็นไปได้หรือไม่ที่จะตรวจพบว่าอยู่ในโหมดออกแบบหรือโหมดรันไทม์จากภายในตัวสร้างของวัตถุ

ฉันตระหนักดีว่าสิ่งนี้อาจเป็นไปไม่ได้และฉันจะต้องเปลี่ยนสิ่งที่ฉันต้องการ แต่ตอนนี้ฉันสนใจคำถามเฉพาะนี้

คำตอบ:


194

คุณสามารถใช้การแจงนับLicenceUsageModeในSystem.ComponentModelเนมสเปซ:

bool designMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);

2
ISite.DesignModeทางออกที่สวยงามมันทำงานได้ดีกว่าการทำงาน C #
56ka

10
@ Filip Kunc: หากไม่ได้ผลใน OnPaint คุณสามารถตรวจสอบเงื่อนไขนี้ในตัวสร้างและเก็บไว้ในฟิลด์คลาส
IMil

3
นอกจากนี้ยังใช้ไม่ได้เมื่อแทนที่ WndProc ในการควบคุมของผู้ใช้ ต้องใช้คำแนะนำ @IMil
Matt Skeldon

1
การวางไว้ในโครงสร้างเป็นความคิดที่ดี IMil มันได้ผลสำหรับฉัน .. ฉันพยายามวางลงในฟิลด์คลาสแบบคงที่ แต่ (ฉันคิดว่า) ฟิลด์คลาสแบบคงที่เริ่มต้นเมื่อคุณเรียกมันครั้งแรกจึงไม่ใช่วิธีที่ปลอดภัย ..
Ibrahim Ozdemir

23

คุณกำลังมองหาสิ่งนี้:

public static bool IsInDesignMode()
{
    if (Application.ExecutablePath.IndexOf("devenv.exe", StringComparison.OrdinalIgnoreCase) > -1)
    {
        return true;
    }
    return false;
}

คุณสามารถทำได้โดยตรวจสอบชื่อกระบวนการ:

if (System.Diagnostics.Process.GetCurrentProcess().ProcessName == "devenv")
   return true;

4
ทำงานใน OnPaint คลาสที่ได้รับตัวสร้าง ฯลฯ ทางออกที่ดีที่สุด
Filip Kunc

14
IMHO นี่ดูเหมือนวิธีแก้ปัญหาที่น่าเกลียด
Camilo Martin

5
โปรดทราบว่าหน่วยความจำรั่วที่นี่ ต้องกำจัดกระบวนการ
nalply

7
แม้ว่าฉันแน่ใจว่าสิ่งนี้จะทำงานได้ดีในกรณีการใช้งานส่วนใหญ่โซลูชันนี้มีข้อบกพร่องหลักประการหนึ่ง: Visual Studio (อย่างน้อยก็ในทางทฤษฎี) ไม่ใช่โฮสต์ของนักออกแบบเพียงรายเดียว devenvดังนั้นการแก้ปัญหานี้จะทำงานหากนักออกแบบของคุณเป็นเจ้าภาพโดยโปรแกรมที่เรียกว่า
stakx - ไม่ร่วมให้ข้อมูลใน

2
ทำงานบน VS2013 ซึ่งแตกต่างจากคำตอบที่ยอมรับในปัจจุบัน
Moby Disk

9

ส่วนประกอบ ... เท่าที่ฉันรู้ไม่มีคุณสมบัติ DesignMode คุณสมบัตินี้จัดทำโดย Control แต่ปัญหาคือเมื่อ CustomControl อยู่ในฟอร์มในตัวออกแบบ CustomControl นี้กำลังทำงานในโหมดรันไทม์

ฉันมีประสบการณ์ว่าคุณสมบัติ DesignMode ทำงานได้ถูกต้องในแบบฟอร์มเท่านั้น


ขอบคุณสำหรับทิป! ฉันไม่เคยตระหนักมาก่อน แต่มันก็สมเหตุสมผลดี การใช้เมธอด LicenseManager ที่ adrianbanks จัดเตรียมไว้จะทำงานได้อย่างสมบูรณ์แบบในกรณีเหล่านี้ซึ่งการควบคุมจะฝังอยู่ในตัวควบคุม / ฟอร์มอื่น +1 ต่อ!
Josh Stribling

1
+1 คุณพูดถูกจริงๆนี่เป็นประสบการณ์ของฉันเช่นกัน เมื่อคุณวางการควบคุมผู้ใช้บนฟอร์มหากมี mouseenter หรือโหลดเหตุการณ์ DesignMode จะยังคงเป็นเท็จเนื่องจากคุณไม่ได้อยู่ในโหมดการออกแบบสำหรับตัวควบคุมนี้ จากประสบการณ์ของฉันมันทำให้วิชวลสตูดิโอพังค่อนข้างยาก
Kyle B

8

การควบคุม (ฟอร์ม UserControls ฯลฯ ) สืบทอดComponent classซึ่งมีbool property DesignModeดังนี้:

if(DesignMode)
{
  //If in design mode
}

4
ซึ่งไม่ได้ตั้งค่าเมื่อตัวสร้างทำงานหรือที่เรียกว่าปัญหาเริ่มต้นของ OP OnHandleCreatedครั้งแรกที่คุณสามารถใช้มันอยู่ใน
Ray

8

สิ่งสำคัญ

การใช้ Windows FormsหรือWPFมีความแตกต่างกันอย่างไร!!

พวกเขามีนักออกแบบที่แตกต่างกันและและความจำเป็นในการตรวจสอบที่แตกต่างกัน นอกจากนี้ยังยุ่งยากเมื่อคุณผสมฟอร์มและตัวควบคุม WPF (เช่น WPF ควบคุมภายในหน้าต่างแบบฟอร์ม)

หากคุณมี Windows Forms เท่านั้นให้ใช้สิ่งนี้:

Boolean isInWpfDesignerMode   = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);

หากคุณมีWPF เท่านั้นให้ใช้การตรวจสอบนี้:

Boolean isInFormsDesignerMode = (System.Diagnostics.Process.GetCurrentProcess().ProcessName == "devenv");

หากคุณมีการใช้งานแบบฟอร์มและ WPF ผสมกันให้ใช้การตรวจสอบดังนี้:

Boolean isInWpfDesignerMode   = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);
Boolean isInFormsDesignerMode = (System.Diagnostics.Process.GetCurrentProcess().ProcessName == "devenv");

if (isInWpfDesignerMode || isInFormsDesignerMode)
{
    // is in any designer mode
}
else
{
    // not in designer mode
}

หากต้องการดูโหมดปัจจุบันคุณสามารถแสดง MessageBox สำหรับการดีบัก:

// show current mode
MessageBox.Show(String.Format("DESIGNER CHECK:  WPF = {0}   Forms = {1}", isInWpfDesignerMode, isInFormsDesignerMode));

สังเกต:

คุณจำเป็นต้องเพิ่ม namespaces System.ComponentModelและSystem.Diagnostics


ฉันคิดว่าการตั้งชื่อของคุณทำให้เข้าใจผิด เมื่อใช้สำหรับ WinForms การตั้งชื่อคือ 'isInWpfDesignerMode' และสำหรับ WPF มันคือ 'isInFormsDesignerMode'
M Stoerzel

5

คุณควรใช้คุณสมบัติ Component.DesignMode เท่าที่ฉันรู้สิ่งนี้ไม่ควรใช้จากตัวสร้าง


7
สิ่งนี้ใช้ไม่ได้เมื่อตัวควบคุมของคุณอยู่ในตัวควบคุมหรือฟอร์มอื่นที่กำลังออกแบบ
Eric

1
จริงๆแล้วมันใช้งานได้ดีในส่วนประกอบของฉัน ฉันต้องเพิ่มif (!DesignMode)วิธีการ OnPaint เสมอเพื่อให้แน่ใจว่าจะไม่สแปมเวลาออกแบบ
Bitterblue

4

อีกวิธีหนึ่งที่น่าสนใจมีอธิบายไว้ในบล็อกนั้น: http://www.undermyhat.org/blog/2009/07/in-depth-a-definitive-guide-to-net-user-controls-usage-mode-designmode-or - โหมดผู้ใช้ /

โดยทั่วไปจะทดสอบสำหรับการดำเนินการแอสเซมบลีที่อ้างอิงแบบคงที่จากแอสเซมบลีรายการ หลีกเลี่ยงความจำเป็นในการติดตามชื่อแอสเซมบลี ('devenv.exe', 'monodevelop.exe' .. )

อย่างไรก็ตามมันใช้ไม่ได้ในสถานการณ์อื่น ๆ ทั้งหมดที่แอสเซมบลีถูกโหลดแบบไดนามิก (VSTO เป็นตัวอย่างเดียว)


ลิงก์เสีย (อย่างมีประสิทธิภาพ) ตอนนี้เปลี่ยนเส้นทางไปยังบล็อกโพสต์ล่าสุด (ปัจจุบัน 2016-03) แทน
Peter Mortensen

3

คุณสามารถใช้สิ่งนี้

if (DesignerProperties.GetIsInDesignMode(this))
{
...
}

คำตอบนี้มีไว้สำหรับ WPF คำถามเกี่ยวกับ WinForms
Rhys Jones

2

ด้วยความร่วมมือของผู้ออกแบบ ... สามารถใช้ใน Controls, Components, ในทุกสถานที่

    private bool getDesignMode()
    {
        IDesignerHost host;
        if (Site != null)
        {
            host = Site.GetService(typeof(IDesignerHost)) as IDesignerHost;
            if (host != null)
            {
                if (host.RootComponent.Site.DesignMode) MessageBox.Show("Design Mode");
                else MessageBox.Show("Runtime Mode");
                return host.RootComponent.Site.DesignMode;
            }
        }
        MessageBox.Show("Runtime Mode");
        return false;
    }

MessageBox.Show(ควรลบเส้นออก มันทำให้ฉันแน่ใจว่ามันทำงานถูกต้องเท่านั้น


1

นี่คือวิธีที่ฉันใช้ในโครงการของฉัน:

//use a Property or Field for keeping the info to avoid runtime computation
public static bool NotInDesignMode { get; } = IsNotInDesignMode();
private static bool IsNotInDesignMode()
{
    /*
    File.WriteAllLines(@"D:\1.log", new[]
    {
        LicenseManager.UsageMode.ToString(), //not always reliable, e.g. WPF app in Blend this will return RunTime
        Process.GetCurrentProcess().ProcessName, //filename without extension
        Process.GetCurrentProcess().MainModule.FileName, //full path
        Process.GetCurrentProcess().MainModule.ModuleName, //filename
        Assembly.GetEntryAssembly()?.Location, //null for WinForms app in VS IDE
        Assembly.GetEntryAssembly()?.ToString(), //null for WinForms app in VS IDE
        Assembly.GetExecutingAssembly().Location, //always return your project's output assembly info
        Assembly.GetExecutingAssembly().ToString(), //always return your project's output assembly info
    });
    //*/

    //LicenseManager.UsageMode will return RunTime if LicenseManager.context is not present.
    //So you can not return true by judging it's value is RunTime.
    if (LicenseUsageMode.Designtime == LicenseManager.UsageMode) return false;
    var procName = Process.GetCurrentProcess().ProcessName.ToLower();
    return "devenv" != procName //WinForms app in VS IDE
        && "xdesproc" != procName //WPF app in VS IDE/Blend
        && "blend" != procName //WinForms app in Blend
        //other IDE's process name if you detected by log from above
        ;
}

ความสนใจ !!!:รหัสที่ส่งคืนบูลแสดงว่าไม่อยู่ในโหมดออกแบบ!


0

โซลูชัน LicenseManager ไม่ทำงานใน OnPaint ไม่ทำสิ่งนี้ ฉันใช้วิธีแก้ปัญหาเดียวกับ @Jarek

นี่คือเวอร์ชันแคช:

    private static bool? isDesignMode;
    private static bool IsDesignMode()
    {
        if (isDesignMode == null)
            isDesignMode = (Process.GetCurrentProcess().ProcessName.ToLower().Contains("devenv"));

        return isDesignMode.Value;
    }

โปรดทราบว่าสิ่งนี้จะล้มเหลวหากคุณใช้ IDE ของบุคคลที่สามหรือถ้า Microsoft (หรือผู้ใช้ปลายทางของคุณ) ตัดสินใจที่จะเปลี่ยนชื่อของไฟล์ปฏิบัติการ VS เป็นอย่างอื่นที่ไม่ใช่ 'devenv' อัตราความล้มเหลวจะต่ำมากเพียงตรวจสอบให้แน่ใจว่าคุณจัดการกับข้อผิดพลาดที่อาจเกิดขึ้นในโค้ดที่ล้มเหลวจากสาเหตุนี้แล้วคุณจะสบายดี


0

ถ้าคุณต้องการรันบางบรรทัดเมื่อรัน แต่ไม่ใช่ในตัวออกแบบ Visual Studio คุณควรใช้คุณสมบัติ DesignMode ดังนี้:

// this code is in the Load of my UserControl
if (this.DesignMode == false)
{
    // This will only run in run time, not in the designer.
    this.getUserTypes();
    this.getWarehouses();
    this.getCompanies();
}

0
    private void CtrlSearcher_Load(object sender, EventArgs e)
    {
           if(!this.DesignMode) InitCombos();
    }

แม้ว่ารหัสนี้อาจตอบคำถามได้ แต่การให้บริบทเพิ่มเติมเกี่ยวกับวิธีการและ / หรือเหตุผลในการแก้ปัญหาจะช่วยเพิ่มมูลค่าในระยะยาวของคำตอบ
Tiago Martins Peres 李大仁

0

ตัวจับเวลาที่เปิดใช้งานโดยค่าเริ่มต้นอาจทำให้เกิดข้อขัดข้องเมื่อใช้การควบคุมแบบกำหนดเอง / ผู้ใช้ ปิดใช้งานตามค่าเริ่มต้นและเปิดใช้งานหลังจากตรวจสอบโหมดการออกแบบเท่านั้น

   public chartAdapter()
    {
        try
        {

            //Initialize components come here
            InitializeComponent();

            //Design mode check
            bool designMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);
            if (designMode)
                return;

            //Enable timers ONLY after designmode check, or else crash
            timerAutoConnect.Enabled = timerDraw.Enabled = true;
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.