mikeo_410


Silverlightアプリケーションの例(1)


  左図をクリックすると、Silverlightアプリケーションを実行します。

  まずは、動作を見ていただいてから、以下の、作り方を読んでいただければと思います。

  ワードをプログラミングに利用すると、どんな使い出か試してみました。
  この例は、文字列の表示に Glyphs を使用し、組み込みフォント odttf を使う例になっています。

  ワードでXPS形式で保存したファイルから得られるXAMLの以下の性質を利用しています。

  1. Canvas、Glyphs、Path と言った少数のコントロールで出来ている。
  2. ほとんどネストはなく、最上位のキャンバスに対する座標でレイアウトされている。
  3. XPS に組み込まれたフォントも利用できる。
  4. XPS に組み込まれたイメージも利用できる。

1.ワードで表示画面を作る

  ワードを数式の記述とボタンの配置に利用します。
  ボタンになる図形と、グラフの表示に使う矩形には、色を付けました。この色は、16進で切の良い値を指定して検索し易くします。長いXAML中から該当箇所を見つける目印にしようと言うもので、色そのものは使いません。
  Blendやデザイナで表示できるなら特にこの工夫はいりません。
  これを、XPS形式で保存します。特に指定をしなかったので、「ドキュメント」に「cos x.xps」と言うファイルが出来ました。

2.Xps2Xamlで変換


  保存した「cos x.xps」をXAMLに変換します。
  「利用局面」には、「SILVERLIGHT」を選びます。

  ここで、あえて「Glyphsを使用」をチェックします。
  Glyphs は TextBlock に置き換えてしまった方が扱い易いのですが、フォントとして odttf が使えると言う特徴を示すためにチェックして置きます。

  設定を確認したら、このウインドウの上に「cos x.xps」をドラッグ、ドロップして貼り付けます。
  出力先のフォルダを指定すると変換がおこなわれます。

  指定したフォルダに、「cos x」フォルダが作られます。
  「cos x」フォルダには、「cosx1P01.xaml」と「Resources」フォルダが作られます。
  「Resources」フォルダには、odttf形式のフォントファイルが複数作られます。
  今回は、イメージファイルはありません。

3.Visual Studio でプロジェクトを作る


  「ファイル」「新規作成」「プロジェクト」で「Silverlightアプリケーション」を作ります。
  プロジェクト名は「sla_xps_glyphs2」としました。

  最初に、odttfファイルをプロジェクトに追加します。
  フォントは、リソースとして組み込みます。
  XAML中では、リソースの Resources/ 以下を参照するように記述されています。

  Visual Studio の「ソリューション エクスプローラ」で「sla_xps_glyphs2」プロジェクトにフォルダを追加します。(プロジェクトを選択して、右ボタンメニューの「追加」「新しいフォルダ」)
  名前を Resources にします。

  追加した、Resources フォルダを選択して、右ボタンメニューの「追加」「既存の項目」を選びます。


  追加するファイルを選択するダイアログが表示されます。
  Xps2Xaml の出力フォルダに移動し、Resourcesフォルダ内のodttfファイル全てを選択して「追加」を押します。

  すると、選択した odttfファイルが、「ソリューション エクスプローラ」の Resources下にコピーされます。

  「ソリューション エクスプローラ」で、odttfを選択して、「プロパティ」を表示して見ると、「ビルドアクション」が「Resource」になっています。
  「ビルドアクション」が「Resource」だと、実行形式ファイル中にリソースとして格納されます。「ソリューション エクスプローラ」のフォルダ構成がリソース上も有効で、プログラム中からは、Resources/xxxx.odttf のように参照できます。

  ※odttfは、使われた文字だけのファイルとのことなので、元を修正したらフォントファイルも差し替える必要があります。(ワードでXPS形式の保存をすると、同じ文書ファイルは、元になったフォントファイルごとに同じ名前が使われるようです。)

4.表示の確認

  プログラミングの前に、XAMLファイルの確認をして置きます。
  自動的に作られた、MainPage.xaml は、以下のようになっています。
  <Grid></Grid>間(6行目)に、cosx1P01.xaml の内容を貼り付けます。
  貼り付けるのは、cosx1P01.xamlの <Page> を除いた <Canvas>...</Canvas>部分です。

  1. <UserControl x:Class="sla_xps_glyphs2.MainPage"
  2.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  3.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
  4.     Width="400" Height="300">
  5.     <Grid x:Name="LayoutRoot" Background="White">
  6.     </Grid>
  7. </UserControl>

  cosx1P01.xaml の最初の部分です。

  1. <Page xml:lang="ja-JP" ShowsNavigationUI="False" xmlns="http://schemas.microsoft.com/xps/2005/06">
  2.   <!--Width=794 Height1123-->
  3.   <Canvas>
  4.     <Canvas.RenderTransform>
  5.       <MatrixTransform Matrix="1.333333333,0,0,1.333333333,0,0" />
  6.     </Canvas.RenderTransform>

  3行目から、ファイルの最後の </Page> を除いて、全て MainPage.xaml の <Grid></Grid>間にコピーします。

  F5を押すと、ビルドして実行され、ワードの表示と同様の表示がブラウザで行われます。
  デザイナーがエラーを表示したり、web.config をデバッグ用に書き換える確認が出たりしますが、ブラウザで表示が出れば良しとしました。

5.プログラミング(XAML)

5.1.Path を Button に

  表示の左側の4つの角丸の矩形をボタンにします。XAML中では <Path> で表されています。
  <Path> は、たくさんあるので、Blend が使えるなら、名前を付けておくと便利です。
  ここでは、色指定を目印にしました。
  ボタンにする、最初の矩形は以下のようになっています。

  1. <Path Data="M 12.533,86.25 C 8.0971,86.25 4.5,89.847 4.5,94.283 L 4.5,126.42 C 4.5,130.85 8.0971,134.45 12.533,134.45 L 237.42,134.45 C 241.85,134.45 245.45,130.85 245.45,126.42 L 245.45,94.283 C 245.45,89.847 241.85,86.25 237.42,86.25 Z ">
  2.     <Path.Fill>
  3.         <SolidColorBrush Color="#FF804040" />
  4.     </Path.Fill>
  5. </Path>

  これを、下記のようにします。

  1. <Button>
  2.     <Button.Template>
  3.         <ControlTemplate>
  4.             <Path MouseLeftButtonDown="cos_Path_MouseLeftButtonDown" Data="M 12.533,86.25 C 8.0971,86.25 4.5,89.847 4.5,94.283 L 4.5,126.42 C 4.5,130.85 8.0971,134.45 12.533,134.45 L 237.42,134.45 C 241.85,134.45 245.45,130.85 245.45,126.42 L 245.45,94.283 C 245.45,89.847 241.85,86.25 237.42,86.25 Z ">
  5.                 <Path.Fill>
  6.                     <LinearGradientBrush x:Name="lgb1"  StartPoint="0.5 0" EndPoint="0.5 1">
  7.                         <LinearGradientBrush.GradientStops>
  8.                             <GradientStop Offset="0" Color="Gray"/>
  9.                             <GradientStop Offset="0.5" Color="AntiqueWhite"/>
  10.                             <GradientStop Offset="1" Color="Gray"/>
  11.                         </LinearGradientBrush.GradientStops>
  12.                     </LinearGradientBrush>
  13.                 </Path.Fill>
  14.                 <VisualStateManager.VisualStateGroups>
  15.                     <VisualStateGroup>
  16.                         <VisualState x:Name="Normal"/>
  17.                         <VisualState x:Name="MouseOver">
  18.                             <Storyboard>
  19.                                 <DoubleAnimation Duration="0" Storyboard.TargetName="lgb1" 
  20.                                                  Storyboard.TargetProperty="Opacity" To="0.7"/>
  21.                             </Storyboard>
  22.                         </VisualState>
  23.                     </VisualStateGroup>
  24.                 </VisualStateManager.VisualStateGroups>
  25.             </Path>
  26.         </ControlTemplate>
  27.     </Button.Template>
  28. </Button>

  もとの <Path> を <Button><Button.Template><ControlTemplate> ... </ControlTemplate></Button.Template></Button> で囲みます。
  もとの <Path> に、MouseLeftButtonDown イベントハンドラを追加します。(MouseLeftButtonDownにハンドラの名前を設定したら、右ボタンメニュー、「イベント ハンドラへ移動」をして、ビハインドコード側にメソッドを作成します。)
  ブラシをグラデーション付きに変えます。
  マウスがボタンの上にあるとき、色を薄くします。

  同様に、後の3か所も修正します。
  <GradientStop> に書いた、Color="Gray" は、グラフの線を黒にしようと言う意図です。
  ボタンごとに、グラフの線の色に対応するように変えてください。

  ※クリックするとイベントハンドラが呼び出されるためには、<Button>は必要ではありません。<Path>にハンドラを設定すれば充分です。<Button>を設定したのは、MouseOverで変化を付けることが目的です。(VisualStateManager.VisualStateGroup以下を有効にするのが目的です。)

5.2.グラフ領域に名前を付ける

  グラフを表示する、右側の矩形を探すと以下のようになっています。

  1. <Path Data="M 262.5,86.25 L 262.5,309.2 L 526.5,309.2 L 526.5,86.25 Z ">
  2.     <Path.Fill>
  3.         <SolidColorBrush Color="#FF808080" />
  4.     </Path.Fill>
  5. </Path>

  これにプログラムから参照できるように名前(chart1)を付け、色を白にして置きます。

  1. <Path Name="chart1" Data="M 262.5,86.25 L 262.5,309.2 L 526.5,309.2 L 526.5,86.25 Z ">
  2.     <Path.Fill>
  3.         <SolidColorBrush Color="White" />
  4.     </Path.Fill>
  5. </Path>

5.3.初期化のタイミングの追加

  最初に一回だけ行う処理を記述できるように、MainPage.xaml に最初からある <Grid> に、Loaded イベントハンドラを追加します。
  また、プログラムから参照できるように、最初の Canvas に名前を付けて置きます。

  1. <UserControl x:Class="sla_xps_glyphs2.MainPage"
  2.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  3.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
  4.     Width="400" Height="300">
  5.     <Grid x:Name="LayoutRoot" Background="White" Loaded="LayoutRoot_Loaded" >
  6.         <Canvas Name="rootCanvas">

6.展開式を計算するクラス


  必要な次数、展開式を計算するクラスを追加しました。

  最終的な、「ソリューション エクスプローラ」の表示は、左図のようになります。

  (「sla_xps_glyphs2.web」プロジェクトは、デバッグ用に自動的に作られるものです。Silverlightアプリケーションのプロジェクトを作るときには、ダイアログが表示され、「Silverlightアプリケーションを新しいWebサイトでホストする」がチェックされていると作られます。この例を動かすには、チェックしてもしなくても差はありません。チェックしないと「sla_xps_glyphs2.web」の代わりに、テスト用のHTMLが自動的に生成されます。このHTMLは「ソリューション エクスプローラ」には表示されませんが、bin/Debugに作られます。
  いずれにしても、Silverlightアプリケーションは、ホストするHTMLを必要とすると言うことです。
  Visual Studioでは、自動生成したHTMLを「スタートアップページ」に設定することで実行しています。これは、右ボタンメニューで変更できます。
  「sla_xps_glyphs2.web」には、他にaspxファイルが2つ作られています。Blendでソリューションを開いたら、Default.aspxが「スタートアップページ」になっていて、実行しても何も表示されませんでした。)

  展開式を、必要な次数計算するクラスでは、コンストラクタに、次数 n を指定して、階乗を計算して置きます。

  Cos(double x)メソッドで、x に対する計算結果を返します。

  1. using System;
  2. using System.Collections.Generic;
  3. namespace sla_xps_glyphs2
  4. {
  5.     public class TaylorExpansionCos
  6.     {
  7.         public TaylorExpansionCos(int n)
  8.         {
  9.             List<double> list = new List<double>();
  10.             double deno = 1;
  11.             list.Add(deno);
  12.             double d = 1;
  13.             for (int i = 1; i <= n; i++)
  14.             {
  15.                 deno *= d++;
  16.                 deno *= d++;
  17.                 list.Add(deno);
  18.             }
  19.             denominator = list.ToArray();
  20.         }
  21.         readonly double[] denominator;
  22.         readonly int[] sign = new int[] { 1, -1 };
  23.         public double Cos(double x)
  24.         {
  25.             double result = 1;
  26.             for (int i = 1; i < denominator.Length; i++)
  27.             {
  28.                 result += sign[i % 2] * Math.Pow(x, i * 2) / denominator[i];
  29.             }
  30.             return result;
  31.         }
  32.     }
  33. }

7.MainPage.xaml の編集

7.1.必要なメソッド

  XAMLを編集してイベントハンドラを追加すると、ビハインドコードである MainPage.xaml に、空のメソッドが作られます。

  1. public partial class MainPage : UserControl
  2. {
  3.     public MainPage()
  4.     {
  5.         InitializeComponent();
  6.     }
  7.     // 最初の Grid  Loadedイベントに設定したハンドラ
  8.     private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
  9.     {
  10.     }
  11.     // cos ボタンのMouseLeftButtonDownイベントハンドラ
  12.     private void cos_Path_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
  13.     {
  14.     }
  15.     // 1次 ボタンのMouseLeftButtonDownイベントハンドラ
  16.     private void b1_Path_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
  17.     {
  18.     }
  19.     // 2次 ボタンのMouseLeftButtonDownイベントハンドラ
  20.     private void b2_Path_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
  21.     {
  22.     }
  23.     // 3次 ボタンのMouseLeftButtonDownイベントハンドラ
  24.     private void b3_Path_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
  25.     {
  26.     }
  27. }

7.2.グラフを書くためのCanvasを追加

  ワードでレイアウトした矩形には、chart1 と名前を付けてあるので、これに新たなキャンバス canvas1 を重ねます。
  canvas1 を、トップレベルのキャンバスに追加して、配置します。

  1. Canvas canvas1;
  2. // 最初の Grid  Loadedイベントに設定したハンドラ
  3. private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
  4. {
  5.     canvas1 = new Canvas();
  6.     //キャンバスのサイズ
  7.     canvas1.Width = chart1.Data.Bounds.Width;
  8.     canvas1.Height = chart1.Data.Bounds.Height;
  9.     //クリップ設定
  10.     RectangleGeometry rg = new RectangleGeometry();
  11.     rg.Rect = new Rect(0, 0, canvas1.Width, canvas1.Height);
  12.     canvas1.Clip = rg;
  13.     //最上位のキャンバスへ追加し配置
  14.     rootCanvas.Children.Add(canvas1);
  15.     Canvas.SetLeft(canvas1, chart1.Data.Bounds.Left);
  16.     Canvas.SetTop(canvas1, chart1.Data.Bounds.Top);
  17. }

7.3.線を引くメソッドの追加

  canvas1 に線を引くメソッドを追加します。
  canvas1 の中央が、原点(0,0)で、x も y も -5 から 5 の範囲を描くものとします。

  1. //chart1の矩形に線を引く。中央が原点で、X、Yとも-5から5を描画する。
  2. void DrawLines(Point[] points, Color color)
  3. {
  4.     double offset_x = chart1.Data.Bounds.Width / 2;
  5.     double offset_y = chart1.Data.Bounds.Height / 2;
  6.     double r_x = chart1.Data.Bounds.Width / 10;
  7.     double r_y = -chart1.Data.Bounds.Height / 10;
  8.     Polyline pl = new Polyline();
  9.     pl.Stroke = new SolidColorBrush(color);
  10.     pl.StrokeThickness = 1;
  11.     foreach (Point p in points)
  12.     {
  13.         double x = p.X * r_x + offset_x;
  14.         double y = p.Y * r_y + offset_y;
  15.         pl.Points.Add(new Point(x, y));
  16.     }
  17.     canvas1.Children.Add(pl);
  18. }

7.4.軸の描画

  最初の Grid の Loadedイベントハンドラに軸の描画を追加します。

  1. // 最初の Grid  Loadedイベントに設定したハンドラ
  2. private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
  3. {
  4.     canvas1 = new Canvas();
  5.     //キャンバスのサイズ
  6.     canvas1.Width = chart1.Data.Bounds.Width;
  7.     canvas1.Height = chart1.Data.Bounds.Height;
  8.     //クリップ設定
  9.     RectangleGeometry rg = new RectangleGeometry();
  10.     rg.Rect = new Rect(0, 0, canvas1.Width, canvas1.Height);
  11.     canvas1.Clip = rg;
  12.     //最上位のキャンバスへ追加し配置
  13.     rootCanvas.Children.Add(canvas1);
  14.     Canvas.SetLeft(canvas1, chart1.Data.Bounds.Left);
  15.     Canvas.SetTop(canvas1, chart1.Data.Bounds.Top);
  16.     //軸の描画
  17.     DrawLines(new Point[] { new Point(-5, 0), new Point(5, 0) }, Colors.Gray);
  18.     DrawLines(new Point[] { new Point(0, 5), new Point(0, -5) }, Colors.Gray);
  19. }

7.4.cos x ボタンのハンドラ

  ボタンがクリックされたら、cos(x)を描画します。100の刻みで計算し、線で結んで描画します。
  最初にある判定は、何度も同じ線をキャンバスに加えないようにしようとしたものです。

  1. // cos ボタンのMouseLeftButtonDownイベントハンドラ
  2. bool cos_enable = true;
  3. private void cos_Path_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
  4. {
  5.     if (!cos_enable) return;
  6.     cos_enable = false;
  7.     int count = 100;
  8.     double x = -5;
  9.     double dx = 10.0 / (count-1);
  10.     Point[] points = new Point[count];
  11.     for (int i = 0; i < count; i++)
  12.     {
  13.         points[i] = new Point(x, Math.Cos(x));
  14.         x += dx;
  15.     }
  16.     DrawLines(points, Colors.Black);
  17. }

7.5. 展開式からの描画サブルーチン

  残ったボタンの処理は次数が異なるだけの同じ処理です。
  n 次の計算結果を描画するようにサブルーチンを用意します。

  1. // n 次の描画用サブルーチン
  2. void nDegDraw(int n, Color color)
  3. {
  4.     int count = 100;
  5.     double x = -5;
  6.     double dx = 10.0 / (count-1);
  7.     Point[] points = new Point[count];
  8.     TaylorExpansionCos tec = new TaylorExpansionCos(n);
  9.     for (int i = 0; i < count; i++)
  10.     {
  11.         points[i] = new Point(x, tec.Cos(x));
  12.         x += dx;
  13.     }
  14.     DrawLines(points, color);
  15. }

7.6.残りのボタンのハンドラ

  このサブルーチンを使って線を描画します。
  最初にある判定は、何度も同じ線をキャンバスに加えないようにしようとしたものです。

  1. // 1次 ボタンのMouseLeftButtonDownイベントハンドラ
  2. bool b1_enable = true;
  3. private void b1_Path_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
  4. {
  5.     if (!b1_enable) return;
  6.     b1_enable = false;
  7.     nDegDraw(1, Colors.Red);
  8. }
  9. // 2次 ボタンのMouseLeftButtonDownイベントハンドラ
  10. bool b2_enable = true;
  11. private void b2_Path_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
  12. {
  13.     if (!b2_enable) return;
  14.     b2_enable = false;
  15.     nDegDraw(2, Colors.Blue);
  16. }
  17. // 3次 ボタンのMouseLeftButtonDownイベントハンドラ
  18. bool b3_enable = true;
  19. private void b3_Path_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
  20. {
  21.     if (!b3_enable) return;
  22.     b3_enable = false;
  23.     nDegDraw(3, Colors.Green);
  24. }

8.フォントに関する注意 

  XPSファイルに含まれるフォントファイルは、ワードで作成した文書で使われた文字のみが格納されています。

  1. ワードの文書を修正し、XPSファイルを変換し直したら、プロジェクトに追加したフォントファイルを差し替える必要があります。
  2. 変換の出力場所を固定できるなら、プロジェクトに追加するとき、「追加ボタン」の右隅のマークのメニューからリンクを選ぶ方法も有効かと思います。
  3. XAML中のGlyphsの UnicodeString を変更する場合は、既出の文字しか使用できないことに注意してください。


mikeo_410@hotmail.com