Skip to content

MS_VSDesignerProblem

nishi_74322014 edited this page Aug 21, 2026 · 1 revision

VSデザイナの問題

概要

VS デザイナには

デザイン時にコードが実行されることにより、

幾つか問題が発生し得る。

補足(この 1 行が本ページの核心): 「デザイン時にコードが実行される
——この事実を知らないと、以降の問題はどれも理解できない。

【VS デザイナが何をしているか】

   フォーム デザイナを開く
     → Visual Studio が【あなたのコードをコンパイルし】
     → 【フォームのインスタンスを実際に生成する】★
     → それを描画してデザイン画面に表示する

   つまり、
     ・コンストラクタが【走る】
     ・フィールド初期化子が【走る】
     ・カスタム コントロールの OnPaint が【走る】
     ・静的コンストラクタが【走る】
【ただし、走らないもの】
   ・Main メソッド(アプリの起動処理)★
   ・Form_Load / Shown(デザイン時は発生しない)
   ・App.config を読む初期化処理(後述の通り一部は読める)
   ・DI コンテナの構築

 → 【「アプリは起動していないのに、フォームだけ生きている」】
   という特殊な状態である

これが問題の根源である。
「アプリが起動していれば当然あるはずのもの」が、
デザイン時には存在しない。

問題

32bit、64bitの問題

VS デザイナは Visual Studio の 32bit プロセス中で動くので、
VS デザイナから実行されるコード中で、64bit の DLL をロードできない。

移行メモ(Visual Studio 2022 で 64bit 化された): 本節の前提は
Visual Studio 2022 で変わった

【Visual Studio 2019 まで】
   devenv.exe は【32bit プロセス】★
     → デザイナも 32bit
     → 64bit 専用の DLL を P/Invoke するコントロールは
       デザイン時に読み込めず、エラーになる

【Visual Studio 2022 以降】
   devenv.exe が【64bit 化】された
     → 逆に【32bit 専用の DLL が読めなくなった】★
     → 古い 32bit の COM / ネイティブ DLL に依存する
       コントロールがデザイン時に落ちるようになった
【つまり、問題が消えたのではなく「向きが逆になった」】
   ・旧来: 64bit DLL が読めない
   ・現在: 32bit DLL が読めない

 → [DLL作成手順](MS_DLLCreationSteps) の
   「32bit / 64bit の一致」(BadImageFormatException)と同じ問題

.NET(Core 系)の Windows Forms デザイナはさらに構造が違う

【.NET Framework のデザイナ】
   Visual Studio の【プロセス内】で直接フォームを生成

【.NET(Core 系)のデザイナ】★
   【別プロセス(デザイナ サーバー)】でフォームを生成し、
   VS とは IPC で通信する
     → VS 本体のビット数に縛られない
     → プロジェクトのターゲット(x86 / x64)に合わせて起動できる
     → 一方で【デザイナ プロセスが落ちる】という新しい症状が出る
        「デザイナー サーバー プロセスとの通信に失敗しました」

回避策:

・プラットフォーム ターゲットを AnyCPU にする
・DesignMode 判定でネイティブ呼び出しを避ける(後述)
・32bit / 64bit の両方を用意し、実行時に切り替える
  ([アンマネージドコードのクロスプラットフォーム化](MS_UnmanagedCodeCrossPlatform))

デザイン時に使用できる値が限られる。

デザイン時に使用できる値は、実行時に使用できる値と異なる。

  • アプリケーションが実行されていないので、
    共有メモリやグローバル変数などのデザイン時に読むことはできない。

  • デザインタイム・プロパティ(Open棟梁のカスタムコントロールのチェック属性のような)は利用可能。

  • app.config の値については、
    以下のようにデザインタイムで利用可能であるもよう。

補足(app.config が「読める」ことの正体): 原文の「利用可能である
もよう」という慎重な書き方は妥当で、
読めるが、読んでいるのは想定と違うファイルである。

【デザイン時に ConfigurationManager が読むもの】
   アプリの App.config【ではなく】
   → 【devenv.exe.config】(Visual Studio 自身の構成ファイル)★

   または、.NET Core のデザイナでは
   → デザイナ サーバー プロセスの構成ファイル

 → 「値が取れない」「null になる」「既定値になる」
   という症状の原因

**参考リンクが示す「ダイナミック プロパティ」**は、
別の仕組みである。

【ダイナミック プロパティ(Windows Forms)】
   デザイナがプロパティ値を App.config に書き出し、
   実行時に【生成されたコードが読み込む】
     → InitializeComponent の中に
       ConfigurationManager.AppSettings[...] を埋める
     → デザイン時に config を読んでいるわけではない ★

【現況】 この機能は現在のデザイナでは推奨されない
         → 設定は [.NET config](MS_DotNetConfig) /
           IOptions パターンで扱う

補足(デザイン時を判定する方法 ── 実務での必須知識): 本ページの
「対策」節が参考リンクのみのため、具体的な手段を補っておく。

// ① Component.DesignMode(最も基本。ただし落とし穴あり)
public partial class MyControl : UserControl
{
    public MyControl()
    {
        InitializeComponent();
        if (!DesignMode)             // ← コンストラクタでは false になる ★
            LoadDataFromDatabase();
    }
}
【DesignMode の落とし穴】★ 最重要
 ① 【コンストラクタの中では常に false】
      → まだデザイナに関連付けられていないため
      → コンストラクタでの判定に使えない
 ② 【入れ子のコントロールでは false】
      → 自分がデザインされている場合は true
      → 親がデザインされ、自分がその子の場合は false になる
 ③ WPF では別の API(後述)
// ② より確実な判定(プロセス名を見る)
static bool IsDesignTime =>
    LicenseManager.UsageMode == LicenseUsageMode.Designtime
    || System.Diagnostics.Process.GetCurrentProcess().ProcessName
         is "devenv" or "DesignToolsServer";   // ← .NET Core のデザイナ ★
// ③ LicenseManager(コンストラクタでも効く)★
public MyControl()
{
    InitializeComponent();
    if (LicenseManager.UsageMode == LicenseUsageMode.Runtime)
        LoadDataFromDatabase();
}

WPF の場合:

// WPF は DesignerProperties を使う
if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
    LoadData();
<!-- XAML では d: 名前空間でデザイン時専用の値を与えられる ★ -->
<UserControl xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d"
             d:DataContext="{d:DesignInstance vm:MyViewModel, IsDesignTimeCreatable=True}">
  <!-- ↑ デザイナ上でだけダミーのデータが表示される。実行時は無視される -->
</UserControl>

d: 名前空間はデザイン時の生産性を大きく上げる
実データがなくてもレイアウトを確認できるためである
XAMLの書き方(1) のバインディングと併用する)。

コントロールの動的追加・削除処理の問題

(子コントロールを持つ Form やカスタム コントロールの)
子コントロールを生成する処理を、コンストラクタに実装した場合、
デザイン時と実行時の表示が乖離する現象が発生する。

補足(なぜ二重に追加されるのか): 別ページで扱われる主題だが、
本ページの「デザイン時にコードが実行される」から自然に導けるので、
仕組みを補っておく。

【二重追加が起きる流れ】

 ① 【デザイン時】
      デザイナがフォームのインスタンスを生成
        → コンストラクタが走る
        → 子コントロールが 1 つ追加される
      ↓
      デザイナが「このフォームには子コントロールが 1 つある」と認識
      ↓
      デザイナが【InitializeComponent に追加コードを書き出す】★
        this.Controls.Add(this.myChild);

 ② 【実行時】
      InitializeComponent が走る … 1 つ追加(デザイナが書いたコード)
      コンストラクタの続きが走る  … もう 1 つ追加(自分で書いたコード)
        → 【合計 2 つ】★
【対策】
 ① コンストラクタで子コントロールを追加しない
      → OnLoad / Loaded イベントで行う
 ② DesignMode(または LicenseManager)で判定して、
    デザイン時には追加しない
 ③ [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    を付け、デザイナに書き出させない ★
 ④ そもそも【デザイナ ファイルを手で編集しない】
      → [*.aspx.designer.cs(vb)を生成する方法](MS_ASPXDesignerGeneration) と
        同じく、生成物は生成させる

対策

下記のような対策の方法がある。

参考

補足(デザイナが壊れたときの切り分け手順): 本ページの内容を踏まえ、
実務で使える手順にまとめておく。

【症状別の原因】

 「デザイナーで例外が発生しました」
   → コンストラクタ or カスタム コントロールの初期化で例外
   → 【スタック トレースを必ず開いて読む】★
      (デザイナのエラー画面に「詳細の表示」がある)

 「型 'Xxx' を読み込めませんでした」
   → ビルドが通っていない/DLL が見つからない
   → 【まずソリューションをビルドし直す】
   → 32/64bit の不一致(前節)

 「デザイナー サーバー プロセスとの通信に失敗しました」(.NET Core)
   → デザイナ プロセスが落ちた
   → VS を再起動、bin/obj を削除

 「開くたびにコントロールの位置がずれる」
   → コンストラクタでレイアウトを変更している
   → デザイナがその結果を .designer.cs に書き戻している ★

 「毎回 .designer.cs に不要な差分が出る」
   → 同上。DesignerSerializationVisibility.Hidden を検討
【設計上の原則】★
 ① コンストラクタには【InitializeComponent 以外を書かない】
      → 初期化は Load / Loaded、または明示的な Init メソッドへ
 ② 【外部リソースにデザイン時に触らない】
      → DB、ファイル、ネットワーク、レジストリ、共有メモリ
 ③ 触る必要があるなら【必ず DesignMode 判定で囲む】
 ④ カスタム コントロールは【デザイン時に落ちないこと】を
    受け入れ条件に含める
      → 落ちると、そのコントロールを使う全画面が編集不能になる ★

なお、根本的な回避策は「デザイナに依存しない」ことである

・WPF / [XAMLの書き方(1)](MS_XAMLWriting1) は
  【XAML を手で書く】のが普通
    → デザイナはプレビューとして使う
    → デザイン時実行の問題に巻き込まれにくい
・[Blazor](MS_Blazor) / Web も同様(デザイナがない)
・Windows Forms でも、動的な画面はコードで組む方が安定する

Tags: 移行, .NET開発, UIサブシステム, Windows Forms, ASP.NET Web Forms

NetDevInfraWiki

マイクロソフト系技術情報 Wiki
Open 棟梁 Wiki

(未着手)

開発基盤部会 Wiki

移行管理: DONETODO

Clone this wiki locally