Phát hiện chế độ thiết kế từ hàm tạo của Điều khiển


99

Tiếp theo từ câu hỏi này , liệu có thể phát hiện xem một cái đang ở chế độ thiết kế hay thời gian chạy từ bên trong hàm tạo của đối tượng không?

Tôi nhận ra rằng điều này có thể không thực hiện được và tôi sẽ phải thay đổi những gì tôi muốn, nhưng hiện tại tôi quan tâm đến câu hỏi cụ thể này.

Câu trả lời:


191

Bạn có thể sử dụng kiểu liệt kê LicenceUsageMode trong System.ComponentModelkhông gian tên:

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

2
Giải pháp thanh lịch, nó hoạt động tốt hơn chức năng C # ISite.DesignMode.
56ka

10
@Filip Kunc: nếu điều này không hoạt động trong OnPaint, bạn có thể kiểm tra điều kiện này trong hàm tạo và lưu trữ nó trong trường lớp.
IMil

3
Điều này cũng không hoạt động khi ghi đè WndProc trong quyền kiểm soát của người dùng. Phải sử dụng @IMil gợi ý
Matt Skeldon

1
đưa nó vào trong quá trình xây dựng là một ý tưởng hay.
Ibrahim Ozdemir

22

Bạn đang tìm thứ gì đó như thế này phải không:

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

Bạn cũng có thể làm điều đó bằng cách kiểm tra tên quy trình:

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

4
Hoạt động trong OnPaint, các lớp dẫn xuất, hàm tạo, v.v. Giải pháp tốt nhất được nêu ra.
Filip Kunc

14
IMHO, đây có vẻ là một giải pháp xấu.
Camilo Martin

5
Chú ý có thể bị rò rỉ bộ nhớ ở đây. Quy trình phải được xử lý.
nalply

7
Mặc dù tôi chắc chắn rằng điều này sẽ hoạt động tốt trong hầu hết các trường hợp sử dụng, nhưng giải pháp này có một lỗ hổng chính: Visual Studio (ít nhất là trên lý thuyết) không phải là máy chủ thiết kế duy nhất. Do đó, giải pháp này sẽ chỉ hoạt động nếu nhà thiết kế của bạn được lưu trữ bởi một ứng dụng được gọi devenv.
stakx - không còn đóng góp vào

2
Hoạt động trên VS2013, không giống như câu trả lời hiện được chấp nhận.
Moby Disk

9

Thành phần ... theo như tôi biết không có thuộc tính DesignMode. Thuộc tính này được cung cấp bởi Control. Nhưng vấn đề là khi CustomControl nằm trong một Biểu mẫu trong trình thiết kế, CustomControl này đang chạy ở chế độ thời gian chạy.

Tôi đã nhận thấy rằng thuộc tính DesignMode chỉ hoạt động đúng trong Biểu mẫu.


Cảm ơn vì tiền hỗ trợ! Tôi chưa bao giờ nhận ra điều đó trước đây, nhưng nó có ý nghĩa hoàn hảo. Sử dụng phương pháp LicenseManager do adrianbanks cung cấp hoạt động hoàn hảo trong những trường hợp này, khi điều khiển được nhúng trong một biểu mẫu / điều khiển khác. +1 cho mỗi!
Josh Stribling

1
+1 Bạn hoàn toàn đúng, đây cũng là kinh nghiệm của tôi. Khi bạn đặt điều khiển người dùng trên một biểu mẫu, nếu có bất kỳ sự kiện di chuột hoặc tải nào, DesignMode vẫn sẽ hiển thị là false vì bạn không ở trong designmode cho điều khiển này. Theo kinh nghiệm của tôi, nó khiến studio hình ảnh bị sập khá nặng.
Kyle B

8

Các điều khiển (Biểu mẫu, UserControls, v.v.) kế thừa Component classbool property DesignModenhư vậy:

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

4
Điều này không được đặt khi phương thức khởi tạo chạy, hay còn gọi là sự cố ban đầu của OP. Thời điểm đầu tiên bạn có thể sử dụng nó là trong OnHandleCreated.
Ray

8

QUAN TRỌNG

Có sự khác biệt khi sử dụng Windows Forms hoặc WPF !!

Họ có các nhà thiết kế khác nhau và cần kiểm tra khác nhau . Ngoài ra, rất phức tạp khi bạn kết hợp các điều khiển Biểu mẫu và WPF. (ví dụ: điều khiển WPF bên trong cửa sổ Biểu mẫu)

Nếu bạn chỉ có Windows Forms , hãy sử dụng cái này:

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

Nếu bạn chỉ có WPF , hãy sử dụng kiểm tra này:

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

Nếu bạn sử dụng hỗn hợp Biểu mẫu và WPF, hãy sử dụng kiểm tra như sau:

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
}

Để xem chế độ hiện tại, bạn có thể hiển thị MessageBox để gỡ lỗi:

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

Nhận xét:

Bạn cần thêm không gian tên System.ComponentModelSystem.Diagnostics .


Tôi nghĩ rằng cách đặt tên của bạn gây hiểu lầm. Khi sử dụng cho WinForms, việc đặt tên là 'isInWpfDesignerMode' và đối với WPF là 'isInFormsDesignerMode'
M Stoerzel

5

Bạn nên sử dụng thuộc tính Component.DesignMode. Theo như tôi biết, điều này không nên được sử dụng từ một phương thức khởi tạo.


7
Điều này không hoạt động khi điều khiển của bạn nằm trong một điều khiển hoặc biểu mẫu khác đang được thiết kế.
Eric

1
Trên thực tế, nó hoạt động khá tốt trong các thành phần của tôi. Tôi luôn phải thêm if (!DesignMode)vào các phương thức OnPaint để đảm bảo rằng nó không spam thời gian thiết kế.
Bitterblue

4

Một phương pháp thú vị khác được mô tả trên blog đó: http://www.undermyhat.org/blog/2009/07/in-depth-a-definitive-guide-to-net-user-controls-usage-mode-designmode-or -chế độ người dùng/

Về cơ bản, nó kiểm tra lắp ráp đang thực thi được tham chiếu tĩnh từ lắp ráp mục nhập. Nó tránh được nhu cầu theo dõi các tên lắp ráp ('devenv.exe', 'monodevelop.exe' ..).

Tuy nhiên, nó không hoạt động trong tất cả các tình huống khác, nơi lắp ráp được tải động (VSTO là một ví dụ).


Liên kết bị phá vỡ (một cách hiệu quả). Thay vào đó, nó chuyển hướng đến bài đăng blog mới nhất (hiện tại là 2016-03).
Peter Mortensen,

3

Với sự hợp tác của nhà thiết kế ... Nó có thể được sử dụng trong Điều khiển, Thành phần, ở mọi nơi

    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(dòng nên được loại bỏ. Nó chỉ làm cho tôi chắc chắn rằng nó hoạt động chính xác.


3

Bạn có thể sử dụng cái này

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

Câu trả lời này dành cho WPF, câu hỏi là về WinForms.
Rhys Jones

1

Đây là phương pháp tôi đã sử dụng trong dự án của mình:

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

Chú ý !!!: Mã trả về bool cho biết KHÔNG đang ở chế độ thiết kế!


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

Mặc dù mã này có thể trả lời câu hỏi, nhưng việc cung cấp thêm ngữ cảnh về cách và / hoặc lý do tại sao nó giải quyết vấn đề sẽ cải thiện giá trị lâu dài của câu trả lời.
Tiago Martins Peres 李大仁

0

Giải pháp LicenseManager không hoạt động bên trong OnPaint, điều này cũng không xảy ra.DesignMode. Tôi đã sử dụng giải pháp tương tự như @Jarek.

Đây là phiên bản đã lưu trong bộ nhớ cache:

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

        return isDesignMode.Value;
    }

Hãy lưu ý rằng điều này sẽ không thành công nếu bạn đang sử dụng bất kỳ IDE nào của bên thứ ba hoặc nếu Microsoft (hoặc người dùng cuối của bạn) quyết định thay đổi tên của tệp thực thi VS thành một cái gì đó khác với 'devenv'. Tỷ lệ thất bại sẽ rất thấp, chỉ cần đảm bảo bạn xử lý mọi lỗi phát sinh có thể xảy ra trong mã không thành công do điều này và bạn sẽ ổn.


0

Nếu bạn muốn chạy một số dòng khi nó đang chạy nhưng không có trong trình thiết kế Visual Studio, bạn nên triển khai thuộc tính DesignMode như sau:

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

Bộ hẹn giờ được bật theo mặc định có thể gây ra sự cố khi sử dụng các điều khiển tùy chỉnh / người dùng. Tắt chúng theo mặc định và chỉ bật sau khi kiểm tra chế độ thiết kế

   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;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.