« [P12]WPFアプリケーション:マウスでテキストボックスをクリックした場合のイベントハンドラーは? | トップページ | WPF:印刷の初めての成功例コード »

[P13]WPF体制下において、デスクトップ・スタンドアロン・プログラムにXAMLをどの程度使うべきか

 私は自分のプログラムをWPF化するにあたって、言語コードのみ(私はC#)でいき、XAMLは、一切使用しないという基本方針になってきました。
 XAMLは、コントロールなどの配置やサイズのコーディングを Visual に補助するものとして、単にサイドで使うに過ぎず、結果はすべてコード化して、自分のライブラリーやアプリケーションを作ることにしました。
 Expression Blend は、不要、仮に使うとしても私には IDE のデザイナーで充分で、Expression Blend を使わなければならないような事情は私に関するかぎりないように思えます。
 まだ、Visual Studio 2008 の日本語版が出たばかりの段階ですが、英語版での実験の結果も含めて、こういう結論になってしまったのです。しかも、XAMLを使用する方向で検討してみた結果なのです。
 
 これは、世間の趨勢・ムードに背を向けています。但し、私は、デスクトップ・スタンドアロン・プログラムのみを手がけている高齢のアマチュア・プログラマーであり、WEB プログラミングは一切しません。プログラミング歴は長い(MSDOS 以前、PC8001以来)のですが、およそ、50個ほどの自己使用の事務処理プログラムを作って、自分で使っているだけに過ぎませんので、デザイナーとプログラマーが分離するわけではありません。そういうプログラミング環境下だけでの話です。

  実は、この記事は最初の記事の書き直しで、最初の記事は、XAML 不使用の可能性も残っていると断りながら、「軽く」XAMLを使っていくという方針のもので、XAML を使うとどういう問題があるのかということをゴタゴタ論じておりました。しかし、その後に私の XAML 離れがさらに決定的になり、冒頭に書いたようなことになりました。

前のように、XAML を使う問題点をゴタゴタ書くのは、微妙な問題に触れることになって大変でもあるし、また各人がそれなりに自分で試してそれなりの確証を得なければ、こういう結論にも至らないでしょうから、それはヤメにいたしました。
  ただ、次の二点だけ指摘しておきます。

 ① XAMLは、『抽象化できない、どこまでも具体的・固定的・静的なままのもの』
   であり、再利用・動的生成に適しないということ。
   その点でリソースという再利用法は用意されているにせよ、抽象化され動的で
   柔軟なDLL とは全く性格を異にする。 

 ② そのような XAMLを言語コードと『二元化した上で連携させるということの代償』
      は、いろいろなところで出てくるのだということ。

 このことを各人が自分の環境下で、どう評価し、どう結論づけるかの問題がある
 のではないか、と思います。

   [注] 私は、Windows 95 の頃から、Borland C++ Builder、2002年からは、
          Visual Studio を使ってきましたが、従来のデザイナーは、言語コードを
          生成するものでした。その限りで、コンパイルに入る段階では、
          既に言語コードに一元化されていました。
      しかし、デザイナーが言語コードと連動せず、XAMLと連携するWPF体制は、
     コンパイルに入る時点では、二元化しているのですから、似て非なる仕組みに
     なったのだと思います。
            私のように、XAMLを使わないということは、今まで相当に慣れ親しんだ
         デザイナーを使わない(使えない)ということになるので、寂しい気もします。
      しかし、それは最終的に言語コードのみにするということであって、サイドで
         デザイナーとXAMLを使いながらデザインをし、確定した数値・配置・色合い等を
         言語コードに取り込むというような使い方ができるわけなので、全くデザイナーを
         失うということではないと思います。

      ただ、コンテナコントロールの大まかな配置については、デザイナーでさえ
    『はがゆい』感じがし、それだけに特化すれば、自分でおおまかな配置をより
    手っ取り早く行う補助的なアプリケーションを先に作り、それを使いながら
    プログラムの書き換えに着手したほうが効率がいいと考え、MyUIDesigner と
    自分で名づけた配置プログラムを作成しました([P9]参照)。
         XAMLを使う場合にも、こういったものを御自分で作られると役に立つのでは
    ないかと思われます。

      そうでもしないと、Canvas を使わないコンテナ・コントロールの組み合わせと
         重ね合わせの作業は、内部に多数のコントロールがひしめき合っているような
         入力画面の場合(私の場合これが多数ある)、想像しただけでも気が
    重くなります。

 では、XAML を捨てたとして、言語コードだけでどう全体を組み立てていったらいいのでしょうか。この点についての現在の私の構想を書いておくことに致します。
 
まず、プロジェクトの中は、App.cs と Window1.cs のみになり、.xaml ファイルはなくなります。 
  
 App.cs 内は、こんな感じでしょうか。partial class にする必要はなくなります。
 
   public class App : Application
    {
      [STAThread]
        static void Main(string[] args)
        {
            new App().Run();
        }
        public App()
        {
            this.Startup += new StartupEventHandler(App_Startup);
        }

        void App_Startup(object sender, StartupEventArgs e)
        {
            Window1 win1 = new Window1();
            win1.Show();

        }
 
 Window1.cs の方は、やはり partial class ではない。

    public class Window1 : Window
    {
        public Window1()
        {
        // InitializeComponent();  不要になります。
        }     
    }

[注] class Window1 について、ちょうどXAMLで扱うユーザーインターフェースの部分
    を別ファイル(UI1.cs)にする、という扱い方もできる。この場合には、partial class
     にしておくことになるが、こうするとWindow1.cs の方がたいへんすっきりする。
    私は、基本的にこの方式を採用することにした。
 
   
問題は、ここから先です。WPF では、あらゆるところがツリー構造化されているように見受けられます。
そこで、XAML ファイルに代わりうる言語コードは次のようにすべきかな、と思っております。

最初にコントロールを生成するコード

  XAML で、最初に Label を作ったところに相当致します。
  必ず、parent を指定して、何らかのコンテナコントロールの中にあるかが決まる構造です。

  public class MonoControl
  {
      public MonoControl()
      {
      }
      
      Label Label_Mono(StackPanel parent, ・・一定の引数・・)
      {//StackPanel に貼り付けるとき使う
           Label lbl = Label_Mono_Common(・・・・);
           parent.Children.Add(lbl);
           return lbl; 
      }
      Label Label_Mono(DockPanel parent, ・・・・)
      {//DockPanel に貼り付けるとき使う
           Label lbl = Label_Mono_Common(・・・・);
           parent.Children.Add(lbl);
           return lbl; 
      }
      Label Label_Mono(Canvas parent, ・・・・)
      {////Canvas に貼り付けるとき使う
           Label lbl = Label_Mono_Common(・・・・);
           parent.Children.Add(lbl);
           return lbl; 
      }
      Label Label_Mono_Common(・・・・)
      {
          Label retlbl = new Label();
          ・・・・
          ・・・・
          return retlbl;
      } 
 
  }
   

  すべて(WPFに関する部分のすべて)を、この構造で統一して作っていけば、必ず Window から階層的に繋がってまいります。
  他方、作られた Label オブジェクトは、戻り値として、上位の構造に上げていき、 最終的な(最上位の)アプリケーションエリアにまで   持ち上げられるようにしてあります。

もちろん、中間層でより大きなかたまりになったときは、戻り値でなくても、上位構造に上げられる工夫をしておけばよいわけです。)
 そうすれば、最下層(実際には、自分のライブラリに置かれることになる)で作られた Label オブジェクトが最上位のアプリケーションの位置まで持ち上がります。 

というわけで、この構造で一貫しておけば、ツリー構造がうまく反映できるのではないでしょうか。

  MonoControl クラスの中には、例えば、TextBox も Button も、また、コンテナ・コントロールである StackPanel や DockPanel なども    この要領で、作成・追加していきます。
 
  そして、例えばこの上位に、StackPanel の中に Label と TextBox が横並びになるものを作っておこうとするなら   
 
  public class SetControl
  {
      public StackPanel pnl;
      public Label lbl;
      //メソッドの戻り値ではもどせないので、上部構造に上げられるように
      public TextBox txb;
      //メソッドの戻り値ではもどせないので、上部構造に上げられるように
      MonoControl monoControl;
          
      public SetControl()
      {
          monoControl = new MonoControl();
      }

      public StackPanel StackPanelwithLabelTextBox(Canvas parent, ・・・・・)
      {//Canvas に貼り付けるとき使う
        pnl = monoControl.Panel_Mono(parent, ・・・・・・);
        StackPanelLabelTextBox_Common(・・・・・・・);
        parent.Children.Add(pnl);
        return pnl;   
      }
    
      public StackPanel StackPanelwithLabelTextBox(DockPanel parent, ・・・・・)
      {//DockPanel に貼り付けるとき使う
        pnl = monoControl.Panel_Mono(parent, ・・・・・・);
        StackPanelLabelTextBox_Common(・・・・・・・);
        parent.Children.Add(pnl);
        return pnl;   
      }

      public void StackPanelwithLabelTextBox_Common(・・・・)
      {
        lbl = monoControl.Label_Mono(pnl, ・・・・・);
        txb = monoControl.TextBox_Mono(pnl, ・・・・);
      }
 
  }

 Grid については、表に利用するため、私は独立のクラスとし、 Column, Row を作り、内部にLabel や TextBox を配置するためのメソッドを持ったものに致しました。Grid の派生クラスにすべきか迷ったのですが、最終的にはそうしないで、ここに示した構造になるように作り上げました。
  もっとも、Grid は、すべきことがいろいろあるので、単なる配置用のものも
独立のクラスにしてあります。このあたりは、人それぞれの問題であるかもしれません。
中間層は、サイズが大きくなるので、通常は独立のクラスになるでしょう。


  このような構造に作っていった場合、これらを使用していく上位構造、最終的にはアプリケーションでは、トップダウンでコーディングすることになります。
    すなわち、Window の下にくるもの、そして更にその中に置かれるもの、という順序でコーディングすることになります。
  そして、XAML コードのように、自動的にツリー構造の繋がりができあがり、わかりやすいものになると思います。 

  私は、この構造で従来のライブラリとは別に、XAML 部分に相当するようなライブラリをもう一つ作り、上記のようなコードを作りあげつつあります。
  完成は、自分のアプリケーションの書き換えと平行させながら、内容を決めていくので、いつになるのかわかりません。
  いまのところ、これで挫折することはないだろうという見通しを持っております。

[P9]の記事内で書いておいたように、この構造で私の第一号WPFアプリケーションは、完成致しました。一応、満足しております。今はその段階です。

《後記》  第5号プログラムまで完成した段階での報告として
  単に5つというのではなく、これで50近くある私のアプリケーションに対する見通しが
 すべて立ったというか、基本的問題点は印刷まで含めて解決した段階(細部の問題
 だけは残っている)です。そのように、5つのアプリケーションを選びました。

  まずは、全体として順調です。
 
 XAML部分に相当するUI部分は、どのアプリケーションも似たような形になります
 から、2つ、3つ作てみると、いわれているように「複雑になる」などという感じは全く
 ありません。まとめ方の要領も、自分のスタイル・パターンができてきます。
 それができると、モデル・プロジェクトを作っておいて、新規作成はIDEのテンプレート
 から生成するのではなく、このモデル・プロジェクトをフォルダーごとコピーし、リネーム
 して使うことができますから、手間がたいへん省けるようになります。
  
  逆に、XAMLとの二元的な管理が、コード一本に一元化され、XAMLの時は、こう
 書いたけれど、コードではどうだっけ、というような負担からも解放され、
 かえって楽で、混乱しません。

  すべて、自分の DLL 相手ですから、動的生成も自在です。
 Grid など、XAML では使いたくもありませんが、DLL で Grid を生成する自分なりの
 Class を作って、Grid の行列数や幅・高さを動的に生成し、内部に必要なコントロール
 まで配置できるようにしておけば、Grid を気楽に使えるようにもなります。
 プロジェクトフォルダーごとコピーして、別の場所に移すのも簡単。
 全体的なプロジェクト名の変更も簡単。

  XAML などは、所詮プロパティを集めただけのものなのですから、言語コードで
 書けるようになっていれば、XAMLなどは簡単に理解していけます(その逆は、
 手間がかかる)。

 要するに、本文で書いておきましたように、XAMLと二元化した代償がすべてなく
 なり、相当の自由が戻ってまいります。


xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
目次に戻る ・・・・ 左欄のカテゴリー 【パソコンの窓】 をクリック
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

|

« [P12]WPFアプリケーション:マウスでテキストボックスをクリックした場合のイベントハンドラーは? | トップページ | WPF:印刷の初めての成功例コード »

コメント

コメントを書く



(ウェブ上には掲載しません)




« [P12]WPFアプリケーション:マウスでテキストボックスをクリックした場合のイベントハンドラーは? | トップページ | WPF:印刷の初めての成功例コード »