Visual StudioのデザイナーでWindowsフォームフォームを開くと、コードにエラーがスローされます。フォームで実際に実行されている場合とは異なり、フォームがデザイナーによって開かれている場合、コード内で分岐し、異なる初期化を実行したいと思います。
フォームを開くデザイナーの一部としてコードが実行されているかどうかを実行時に判断するにはどうすればよいですか?
「デザインモード」になっているかどうかを確認するには:
if (System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime)
{
// Design time logic
}
Control.DesignModeプロパティは、おそらく探しているものです。コントロールの親がデザイナーで開いているかどうかを示します。
ほとんどの場合、うまく機能しますが、期待どおりに機能しない場合があります。まず、コントロールコンストラクターでは機能しません。第二に、DesignModeは「孫」コントロールに対してfalseです。たとえば、UserControlが親でホストされている場合、UserControlでホストされているコントロールのDesignModeはfalseを返します。
非常に簡単な回避策があります。次のようになります。
public bool HostedDesignMode
{
get
{
Control parent = Parent;
while (parent!=null)
{
if(parent.DesignMode) return true;
parent = parent.Parent;
}
return DesignMode;
}
}
私はそのコードをテストしていませんが、should動作します。
最も信頼できるアプローチは次のとおりです。
public bool isInDesignMode
{
get
{
System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess();
bool res = process.ProcessName == "devenv";
process.Dispose();
return res;
}
}
これを行う最も確実な方法は、DesignModeプロパティを無視し、アプリケーションの起動時に設定される独自のフラグを使用することです。
クラス:
public static class Foo
{
public static bool IsApplicationRunning { get; set; }
}
Program.cs:
[STAThread]
static void Main()
{
Foo.IsApplicationRunning = true;
// ... code goes here ...
}
次に、必要なときにフラグをチェックします。
if(Foo.IsApplicationRunning)
{
// Do runtime stuff
}
else
{
// Do design time stuff
}
設計者が独自のプロセスを持つようになったため、VS2012ではdevenvアプローチが機能しなくなりました。私が現在使用しているソリューションは次のとおりです( 'devenv'部分はレガシー用に残されていますが、VS2010なしではテストできません)。
private static readonly string[] _designerProcessNames = new[] { "xdesproc", "devenv" };
private static bool? _runningFromVisualStudioDesigner = null;
public static bool RunningFromVisualStudioDesigner
{
get
{
if (!_runningFromVisualStudioDesigner.HasValue)
{
using (System.Diagnostics.Process currentProcess = System.Diagnostics.Process.GetCurrentProcess())
{
_runningFromVisualStudioDesigner = _designerProcessNames.Contains(currentProcess.ProcessName.ToLower().Trim());
}
}
return _runningFromVisualStudioDesigner.Value;
}
}
Visual Studio Express 2013でも同じ問題が発生しました。ここで提案された多くの解決策を試しましたが、私にとって有効だったのは 別のスレッドへの回答 でした。壊れている:
protected static bool IsInDesigner
{
get { return (Assembly.GetEntryAssembly() == null); }
}
using (System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess())
{
bool inDesigner = process.ProcessName.ToLower().Trim() == "devenv";
return inDesigner;
}
上記のコード(usingステートメントを追加)を試してみましたが、これは場合によっては失敗します。起動時にデザイナーが読み込まれるフォームに直接配置されたユーザーコントロールのコンストラクターでテストします。しかし、他の場所でも機能します。
すべての場所で私のために働いたのは:
private bool isDesignMode()
{
bool bProcCheck = false;
using (System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess())
{
bProcCheck = process.ProcessName.ToLower().Trim() == "devenv";
}
bool bModeCheck = (System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime);
return bProcCheck || DesignMode || bModeCheck;
}
ちょっとやり過ぎかもしれませんが、うまくいくので、私には十分です。
上記の例での成功はbModeCheckであるため、おそらくDesignModeは余剰です。
/// <summary>
/// Are we in design mode?
/// </summary>
/// <returns>True if in design mode</returns>
private bool IsDesignMode() {
// Ugly hack, but it works in every version
return 0 == String.CompareOrdinal(
"devenv.exe", 0,
Application.ExecutablePath, Application.ExecutablePath.Length - 10, 10);
}
ハックっぽいですが、 VB.NET を使用していて、Visual Studio内から実行している場合My.Application.Deployment.CurrentDeploymentはまだデプロイされていないため、Nothingになります。 C#で同等の値を確認する方法がわかりません。
System.Diagnostics.Debugger.IsAttached
デバッグモードでの実行が実際にカウントされるかどうかはわかりませんが、簡単な方法は、System.Diagnostics.Debugger.IsAttached
をチェックするif
ステートメントをコードに含めることです。
プロジェクトを実行すると、名前に「.vshost」が追加されます。
だから、私はこれを使用します:
public bool IsInDesignMode
{
get
{
Process p = Process.GetCurrentProcess();
bool result = false;
if (p.ProcessName.ToLower().Trim().IndexOf("vshost") != -1)
result = true;
p.Dispose();
return result;
}
}
わたしにはできる。
設計時にまったく必要のないプロパティを作成した場合は、DesignerSerializationVisibility属性を使用して非表示に設定できます。例えば:
_protected virtual DataGridView GetGrid()
{
throw new NotImplementedException("frmBase.GetGrid()");
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public int ColumnCount { get { return GetGrid().Columns.Count; } set { /*Some code*/ } }
_
NotImplementedException()
を使用してフォームに変更を加えて保存しようとするたびに、Visual Studioのクラッシュが停止しました。代わりに、Visual Studioはこのプロパティをシリアル化しないことを知っているため、スキップできます。フォームのプロパティボックスに奇妙な文字列を表示するだけですが、無視しても安全です。
この変更は、再構築するまで有効にならないことに注意してください。
UserControlsで次のコードを使用し、作業を行います。他のメンバーから指摘されたカスタムユーザーコントロールを使用するアプリでは、DesignModeのみを使用しても機能しません。
public bool IsDesignerHosted
{
get { return IsControlDesignerHosted(this); }
}
public bool IsControlDesignerHosted(System.Windows.Forms.Control ctrl)
{
if (ctrl != null)
{
if (ctrl.Site != null)
{
if (ctrl.Site.DesignMode == true)
return true;
else
{
if (IsControlDesignerHosted(ctrl.Parent))
return true;
else
return false;
}
}
else
{
if (IsControlDesignerHosted(ctrl.Parent))
return true;
else
return false;
}
}
else
return false;
}
コントロールのDesignMode
プロパティを確認します。
if (!DesignMode)
{
//Do production runtime stuff
}
コンポーネントはまだ初期化されていないため、これはコンストラクターでは機能しません。
System.ComponentModel.Component.DesignMode == true
もう1つあります。
//Caters only to thing done while only in design mode
if (App.Current.MainWindow == null){ // in design mode }
//Avoids design mode problems
if (App.Current.MainWindow != null) { //applicaiton is running }
フォームまたはコントロールを使用している場合は、DesignModeプロパティを使用できます。
if (DesignMode)
{
DesignMode Only stuff
}
少なくとも以前のバージョンのVisual Studioでは、DesignModeプロパティにバグがあることがわかりました。したがって、次のロジックを使用して独自に作成しました。
Process.GetCurrentProcess().ProcessName.ToLower().Trim() == "devenv";
一種のハック、私は知っているが、それはうまく機能します。
ここでほとんどの回答をテストした後、残念なことに何もうまくいきませんでした(VS2015)。そこで、DesignModeはControlクラスの保護されたプロパティであるため、 JohnVの答え に少しひねりを加えました。
最初に、Reflectionを介してDesignModeのProperty値を返す拡張メソッドを作成しました。
public static Boolean GetDesignMode(this Control control)
{
BindingFlags bindFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static;
PropertyInfo prop = control.GetType().GetProperty("DesignMode", bindFlags);
return (Boolean)prop.GetValue(control, null);
}
そして、JohnVのような関数を作成しました。
public bool HostedDesignMode
{
get
{
Control parent = Parent;
while (parent != null)
{
if (parent.GetDesignMode()) return true;
parent = parent.Parent;
}
return DesignMode;
}
}
これは私のために働いた唯一の方法であり、ProcessNameの混乱をすべて回避し、反射は軽く使用すべきではありませんが、この場合はすべての違いがありました! ;)
編集:
2番目の関数を次のような拡張メソッドにすることもできます。
public static Boolean IsInDesignMode(this Control control)
{
Control parent = control.Parent;
while (parent != null)
{
if (parent.GetDesignMode())
{
return true;
}
parent = parent.Parent;
}
return control.GetDesignMode();
}
問題を解決するには、次のようにコーディングすることもできます。
private bool IsUnderDevelopment
{
get
{
System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess();
if (process.ProcessName.EndsWith(".vshost")) return true;
else return false;
}
}