何となく Blog by Jitta
Microsoft .NET 考

目次

Blog 利用状況
  • 投稿数 - 761
  • 記事 - 18
  • コメント - 35954
  • トラックバック - 222
ニュース
  • IE7以前では、表示がおかしい。div の解釈に問題があるようだ。
    IE8の場合は、「互換」表示を OFF にしてください。
  • 検索エンジンで来られた方へ:
    お望みの情報は見つかりましたか? よろしければ、コメント欄にどのような情報を探していたのか、ご記入ください。
It's ME!
  • はなおか じった
  • 世界遺産の近くに住んでます。
  • Microsoft MVP for Visual Developer ASP/ASP.NET 10, 2004 - 9, 2011
広告

記事カテゴリ

書庫

日記カテゴリ

ギャラリ

その他

わんくま同盟

同郷

 

前回のあらすじ。開発環境が整った。今回は、グラフを描くための準備、どのようにしたらグラフがかけるのかを知ることが目標。


まず、遊んでみる。Silverlight プロジェクトを作る。Web サイトにするか、Web プロジェクトにするか、HTML を作るか、聞いてくる。ん???とりあえず配置の予定はないし、表示が確認できればよいので、HTML にする。

Page.xaml というファイルが、デザイン状態で表示される。ツールボックスを見ると、コントロールが並んでいる。グラフを作るので、ラインがあるかな・・・あった。これを、ドラッグ・・・できないorz

ん~?どうも、ビジュアル デザイナには、ドラッグできないもよう。XAML エディタの方にはドラッグできる。なので、XAML へドロップしてみる。XAML は変わったけど、デザイナの方には何も表示されないorz

とりあえず、<Line にカーソルを持って行き、スペース キーを押してみる。インテリセンスが表示される。一通り眺めると、「X1」とか「X2」とかいうプロパティ(属性)があることがわかる。これだろう。X1,Y1 を、10,10、X2,Y2 を、100,100 にしてみる。で、出ない・・・。

さらに眺める。Stroke ってなんだ?StrokeLineJoin とか、StrokeDashArray というのがある。Join は線の終端の形状、DashArray は破線を描くときの線と破れ目の形状を指定するものだろう。これかもしれない。入力してみる。値の入力候補に、色の名前が出てくる。当たり!Black を選択。やっと線が引けた。

グラフを描くときには、コード上で線を追加することになるが、そのときに設定しなければならない属性が、これでわかった。X1, Y1, X2, Y2, Stroke は、最低限設定しなければならない。デザイナに追加したコントロールをコードで操作するには x:Name を指定する必要があるが、コードからは変更できない(ReadOnly)のようだ。オブジェクトそのものを指定すればいいから、要らないのかな?

では、コードで追加できるか、やってみる。Page.xaml.cs を開く。コンストラクタに、コードを追加する。

// コンストラクタへ追加
public Page() {
    InitializeComponent();
    System.Windows.Media.Line l = new Line();
    l.X1 = 100;
    l.Y1 = 10;
    l.X2 = 10;
    l.Y2 = 100;
    l.Stroke = ...
}

はて、困った。Stroke に設定する、色はどうやって指定するの?インテリセンスによると、ここは Brush を設定するらしい。ということは、規定の Brush が、Brushes に用意されているはずだ!!(WindowsForms での経験より)………Brushes がない???

困った。困ったときは [F1]!!カーソルを、l.Stroke の、Stroke に置いて、押してみる。System.Windows.Shapes から出てくる。え~っと。これって、WPF?仕方がないので、目次より、[Microsoft Silverlight 2 SDK → Silverlight 2 Beta 1 - Development with the .NET Framework → Silverlight Reference → System.Windows.Media Namespace] を参照する。ここから、Brush へジャンプ。

For XAML syntaxes that take a Brush, you need to specify one of the following:

  • A Color, specified as a string to directly fill a Brush-type property in XAML attribute form. That string is implied to create a SolidColorBrush to fill the value, and the Color you specify becomes the Color property value.

  • A nonabstract derived type of Brush as an object element, with the Brush-type property in question being specified in property element form. For details, see the XAML syntax on the reference pages for SolidColorBrush, LinearGradientBrush, RadialGradientBrush, ImageBrush, and VideoBrush.

For more information and examples of the XAML syntax and illustrations of the types of brushes, see Brushes (Silverlight 2).

ん~~~。今のところ、SolidColorBrush でいいみたい。こいつのオブジェクトを作ればいい、と。で、SolidcolorBrush へジャンプ。コンストラクタを見ると、Color を指定する...はいはい。

やっぱり、また、眺める。なんだ、Colors なんてのがあるやん。これ。

// コンストラクタへ追加
public Page() {
    InitializeComponent();
    System.Windows.Media.Line l = new Line();
    l.X1 = 100;
    l.Y1 = 10;
    l.X2 = 10;
    l.Y2 = 100;
    l.Stroke = new SolidColorBrush(Colors.Black);
}

これで実行!!でない...

そういえば、WindowsFoms ではコンテナに追加してやらないとダメだったな。Silverlight の場合、コンテナって、どれだ?ってことで、XAML を見る。LayoutRoot なんて名前のコントロールがある。こいつに違いない。ってことでメンバ一覧見ると、案の定、Children なんてのがある。こいつに追加する。

// コンストラクタへ追加
public Page() {
    InitializeComponent();
    System.Windows.Media.Line l = new Line();
    l.X1 = 100;
    l.Y1 = 10;
    l.X2 = 10;
    l.Y2 = 100;
    l.Stroke = new SolidColorBrush(Colors.Black);
    this.LayoutRoot.Children.Add(l);
}

これで実行!!よし、表示された。

さて、他のもついでに見ておく。・・・PolyLineSegment クラスなんてのがある。PointCollection を受け取って、それぞれの Point 間をつなぐ線を引く、と。折れ線部分はこれが使えそう。早速試す。

試す前に、今度は説明を読む。StartPoint を設定して、そこから PointCollection の最初の要素へ線が引かれるらしい。というより、PathFigure クラスに設定するもの、だな、これは。ってことで、PathFigure をみる。Properties に、StartPoint と、Segments がある。Segments に、PolyLineSegment などのオブジェクトを放り込んで使うものだな、きっと。

では、早速やってみる。


public Page() {
    InitializeComponent();
    Line l = new Line();
    l.X1 = 100;
    l.X2 = 10;
    l.Y1 = 10;
    l.Y2 = 100;
    l.Stroke = new SolidColorBrush(Colors.Black);
    LayoutRoot.Children.Add(l);

    PathFigure pf = new PathFigure();
    PolyLineSegment poly = new PolyLineSegment();
    poly.Points.Add(new Point(10, 10));
    poly.Points.Add(new Point(100, 10));
    poly.Points.Add(new Point(100, 100));
    poly.Points.Add(new Point(10, 100));
    pf.StartPoint = new Point(10, 100);
    pf.Segments.Add(poly);
    LayoutRoot.Children.Add(pf);
}

PathFigure を、UIElement に変換できません、だそうです。。。そ、そういうところまで、見てなかったねぇ。

改めて、PathFigure Class の、例示されているコードを見る。XAML なのね。Canvas の中に Path があって、その Data プロパティに PathGeometry があって、それの Figures が、PathFigure になっている。ということは、PathFigure をさらに Path に入れればいい?

早速修正してみる。


public Page() {
    InitializeComponent();
    Line l = new Line();
    l.X1 = 100;
    l.X2 = 10;
    l.Y1 = 10;
    l.Y2 = 100;
    l.Stroke = new SolidColorBrush(Colors.Black);
    LayoutRoot.Children.Add(l);

    PolyLineSegment poly = new PolyLineSegment();
    poly.Points.Add(new Point(10, 10));
    poly.Points.Add(new Point(100, 10));
    poly.Points.Add(new Point(100, 100));
    poly.Points.Add(new Point(10, 100));
    PathFigure pf = new PathFigure();
    pf.StartPoint = new Point(10, 100);
    pf.Segments.Add(poly);
    PathGeometry pg = new PathGeometry();
    pg.Figures.Add(pf);
    Path p = new Path();
    p.Stroke = new SolidColorBrush(Colors.Blue);
    p.Data = pg;
    LayoutRoot.Children.Add(p);
}

実行してみる。何も表示されない...orz

なぜ?なぜ?なぜ?とりあえず、どこまで実行されているのかわからないので、今追加した、PolyLineSegment 以降の行をコメントアウトする。そして、1行ずつコメントを外しながら、実行する。

すると、pf.Segment.Add(poly); の行のコメントアウトを外すと、何も出なくなる事がわかった。もしかすると、例外が発生している?

ここの説明を見ていて、「gets or sets...」と書かれていることが気になったのよ。WindowsForm では、こういうコレクション クラスを扱うプロパティは、get しかできない。なのに、どうして set もできるの?もしかして、コンストラクタでは自動で作らない?

ってことで、コードを修正する。きっと PathGeometry の Figures も同じに違いない。


public Page() {
    InitializeComponent();
    Line l = new Line();
    l.X1 = 100;
    l.X2 = 10;
    l.Y1 = 10;
    l.Y2 = 100;
    l.Stroke = new SolidColorBrush(Colors.Black);
    LayoutRoot.Children.Add(l);

    PolyLineSegment poly = new PolyLineSegment();
    poly.Points.Add(new Point(10, 10));
    poly.Points.Add(new Point(100, 10));
    poly.Points.Add(new Point(100, 100));
    poly.Points.Add(new Point(10, 100));
    PathFigure pf = new PathFigure();
    pf.StartPoint = new Point(10, 100);
    pf.Segments = new PathSegmentCollection();
    pf.Segments.Add(poly);
    PathGeometry pg = new PathGeometry();
    pg.Figures = new PathFigureCollection();
    pg.Figures.Add(pf);
    Path p = new Path();
    p.Stroke = new SolidColorBrush(Colors.Blue);
    p.Data = pg;
    LayoutRoot.Children.Add(p);
}

実行する。青い四角の中に黒いバッテンになった。


さて、マウスポインタが乗ったときに色が変わると、いいことがあるかもしれない。ということで、それも考えておく。

たぶん、アニメーションの一種だろう。当然、[Silverlight 2 Beta 1 - Development with the .NET Framework] の下にあるはずだ。きっと、[Core Presentation Framework / UI] にあるに違いない。ほら、あった [Animation] が。で、見てみる。[Animation Overview] を、ざっと読む。フェードイン、フェードアウトの例がある。で、DoubleAnimation を作って、Storyboard を作るらしい。

では、DoubleAnimation を見てみる。これは、double 型のプロパティを変化させるためのものらしい。今回は、Color を変えたいので、階層の上、Timeline に戻ってみる。すると、ColorAnimation があるのがわかる。これを見る。

要は、From と To を指定して、Duration に何秒かけてアニメーションするか、を指定すればいいらしい。そして、Storyboard に組み込む、と。マウスを当てると瞬時に赤になり、離すと1秒かけて青に戻る、とする。


Storyboard colorChangeStory;

public Page() {
    ...略
    ColorAnimation colorAnime = new ColorAnimation();
    colorAnime.AutoReverse = false;
    colorAnime.Duration = new Duration(new TimeSpan(0, 0, 1));
    colorAnime.From = Colors.Red;
    colorAnime.To = Colors.Blue;
    colorChangeStory = new Storyboard();
    colorChangeStory.Children.Add(colorAnime);

    Storyboard.SetTarget(colorChangeStory, p);
    Storyboard.SetTargetProperty(colorChangeStory, "Color");

    p.MouseEnter += new MouseEventHandler(PathMouseEnter);
    p.MouseLeave += new MouseEventHandler(PathMouseLeave);

    LayoutRoot.Children.Add(p);
}
void PathMouseEnter(object sender, MouseEventArgs e) {
    Path p = sender as Path;
    if (p == null) { return; }
    p.Stroke = new SolidColorBrush(Colors.Red);
}
void PathMouseLeave(object sender, MouseEventArgs e) {
    colorChangeStory.Begin();
}

こんな感じかな。実行してみる。・・・何も起こらない。なんで?

例示されているコードを見ると、Storyboard をリソースに登録しなければいけないらしい。では、追加する。


public Page() {
    ...略
    LayoutRoot.Resources.Add(colorChangeStory);
    LayoutRoot.Children.Add(p);
}

これでどうだ?消えた...

ストーリーボードを実行するときに、例外が発生しているらしい。たぶん、Color のプロパティ指定が間違っているんだろうな。ColorAnimate のサンプルを見ると、"(Panel.BackgroundColor).(SolidColorBrush.Color)"となっている。ん~?じゃぁ、「Stroke に設定する SolidColorBrush の Color プロパティ」の様な設定になるわけ?試す。


public Page() {
    ...略
    Storyboard.SetTarget(colorChangeStory, p);
    Storyboard.SetTargetProperty(colorChangeStory, "(Stroke).(SolidColorBrush.Color)");
    略...
}

これでどうだ!!・・・うまくいった。ふぅ。。。

今日のおさらい。

  • マニュアルは、注意深く読むこと。

  • コレクション クラスのプロパティは、インスタンス化してやらないといけない場合がある。

  • 描き始めは、StartPoint で指定する。

  • オブジェクトの階層が深くて大変。。。

  • この連載では、XAML を扱うことはなさそう。

解決させていない疑問点。

  • 複数の動きをさせるには?たとえば、「色を変えながら、幅も変える」など。

  • Storyboard とオブジェクトは、1:1 で結びつくようだ。では、1つの動きを複数のオブジェクトで共有することはできない?たとえば、折れ線が2つ、3つになったとき、すべての折れ線に「ポイントされたら赤い色に変える。ポイントが外れたら元の色に戻す。」といった動きをさせたい。To のみ指定すれば、「赤い色に変える」は共有できる。

投稿日時 : 2008年5月22日 21:11
コメント
タイトル  
名前  
Url
コメント