none
WPFで、○の画像の上に数字や文字を入れて、1列に並べたい RRS feed

  • 質問

  • いつもお世話になります。
    VisualC#2010、WindowsXPでの動作について質問があります。
    WPFで、○の画像の上に数字や文字を入れて、1列に並べたいと思っています。
    重ねるのにCanvasを使い、並べるのにStackPanelを使ってみました。
    (A)(B)(C)
    みたいにです。

    StackPanel horizontalpanel = new StackPane();
    horizontalpanel.Orientation = Orientation.Horizontal;
    BitmapImage circleBmp = new BitmapImage(circleFileName);
    Image circleImage = new Image();
    circleImage.Source = circleBmp;

    string[] words = {"A","B","C"};

    foreach(string word in words) {
     TextBlock textblock = new TextBlock();
     textblock.Text = word;
     Canvas canvas = new Canvas();
     canvas.Children.Add(textblock);
     canvas.Children.Add(circleImage);
     horizontalpanel.Children.Add(canvas);
    }

    で、これを実行すると、変に重なってしまいます。
    どのようにしたらよいか、アドバイスお願いします。

    2010年9月24日 11:00

回答

  • Canvas の Width/Height を設定しないと、Canvas は自身の横幅を決定できません(Canvas は自身の大きさを決定するときに子要素の配置を考慮しません)。そのため、StackPanel の最後の要素以外は幅 0 でレンダリングされます。

    個人的には、この場合なら ItemsControl を使ってバインディングしますね。ItemsPanel を使って横方向への StackPanel にしておき、ItemTemplate で Grid を使って背景と文字を重ねます。

    • 回答としてマーク HANA01 2010年9月24日 14:06
    2010年9月24日 13:38
  • 現象が再現できました。確かに、重なってしまいますね。調べてみたところ、下記のページを見つけました。

    http://stackoverflow.com/questions/1205851/problem-adding-canvasses-to-a-stackpanel-in-code-in-wpf

    CanvasをStackPanelに追加するとき、WidthやHeightを指定しないと上手く表示されないみたいですね。試しにWidthを指定したら、重ならずに表示されました。

    StackPanel horizontalpanel = new StackPanel();
    horizontalpanel.Orientation = Orientation.Horizontal;
    
    Uri circleFileName = new Uri("画像のURI", UriKind.Relative);
    BitmapImage circleBmp = new BitmapImage(circleFileName);
    
    string[] words = { "A", "B", "C" };
    
    foreach (string word in words)
    {
      TextBlock textblock = new TextBlock();
      textblock.Text = word;
    
      Image circleImage = new Image();
      circleImage.Source = circleBmp;
    
      Canvas canvas = new Canvas();
    
      // Width を表示したら重ならずに表示される
      canvas.Width = 300;
    
      Canvas.SetLeft(circleImage, 10);
      Canvas.SetTop(circleImage, 10);
      Canvas.SetLeft(textblock, 50);
      Canvas.SetTop(textblock, 50);
      canvas.Children.Add(circleImage);
      canvas.Children.Add(textblock);
    
      horizontalpanel.Children.Add(canvas);
    }
    
    


    なかむら(http://d.hatena.ne.jp/griefworker)
    • 回答としてマーク HANA01 2010年9月27日 6:33
    2010年9月24日 14:03

すべての返信

  • で、これを実行すると、変に重なってしまいます。

    どのようにしたらよいか、アドバイスお願いします。

    「変に重なってしまう」とは、どういうことでしょうか?画像の上に文字が表示されない、ということですか?

    もしそうだとすると、Canvas に追加する順が textblock → circleImage なので、circleImage が textblock の上に配置されてしまっているためだと思います。

    circleImage の後に textblock を Canvas に追加すれば、画像の上に文字を表示できるはずです。(試していませんが…)

     


    なかむら(http://d.hatena.ne.jp/griefworker)
    2010年9月24日 11:21
  • なかむらさん、いつもありがとうございます。
    変な、というのは、canvasには重ねて表示して、そのあとpanelには並べて表示する、と書いているつもりなのですが、○の画像も数字もぜんぶ重なって1か所に表示されてしまいます。
    順番を入れ替えてみても同様でした。
    panelへの追加がうまくいっていないのだとはわかるのですが、どうすればそれを解消できるのかがよくわからない状況です。
    ちなみに、canvasを使わず、textblockも使わずに、単にImageをpanelに追加すれば、順番にならんで追加できます。
    ○○○
    のようになります。
    2010年9月24日 13:08
  • Canvas の Width/Height を設定しないと、Canvas は自身の横幅を決定できません(Canvas は自身の大きさを決定するときに子要素の配置を考慮しません)。そのため、StackPanel の最後の要素以外は幅 0 でレンダリングされます。

    個人的には、この場合なら ItemsControl を使ってバインディングしますね。ItemsPanel を使って横方向への StackPanel にしておき、ItemTemplate で Grid を使って背景と文字を重ねます。

    • 回答としてマーク HANA01 2010年9月24日 14:06
    2010年9月24日 13:38
  • 現象が再現できました。確かに、重なってしまいますね。調べてみたところ、下記のページを見つけました。

    http://stackoverflow.com/questions/1205851/problem-adding-canvasses-to-a-stackpanel-in-code-in-wpf

    CanvasをStackPanelに追加するとき、WidthやHeightを指定しないと上手く表示されないみたいですね。試しにWidthを指定したら、重ならずに表示されました。

    StackPanel horizontalpanel = new StackPanel();
    horizontalpanel.Orientation = Orientation.Horizontal;
    
    Uri circleFileName = new Uri("画像のURI", UriKind.Relative);
    BitmapImage circleBmp = new BitmapImage(circleFileName);
    
    string[] words = { "A", "B", "C" };
    
    foreach (string word in words)
    {
      TextBlock textblock = new TextBlock();
      textblock.Text = word;
    
      Image circleImage = new Image();
      circleImage.Source = circleBmp;
    
      Canvas canvas = new Canvas();
    
      // Width を表示したら重ならずに表示される
      canvas.Width = 300;
    
      Canvas.SetLeft(circleImage, 10);
      Canvas.SetTop(circleImage, 10);
      Canvas.SetLeft(textblock, 50);
      Canvas.SetTop(textblock, 50);
      canvas.Children.Add(circleImage);
      canvas.Children.Add(textblock);
    
      horizontalpanel.Children.Add(canvas);
    }
    
    


    なかむら(http://d.hatena.ne.jp/griefworker)
    • 回答としてマーク HANA01 2010年9月27日 6:33
    2010年9月24日 14:03
  • Hongliangさん、ありがとうございました。
    HightとWidthを設定して期待通りの表示になりました。
    2010年9月24日 14:06
  • 先日のCanvasで、画像/文字をクリックしたときに、処理をしたいのですが、どのようにイベントハンドラを登録したらよいでしょう?

    TextBlock textblock = new TextBlock();
    textblock.Text = word;

    textblock.Click += (s,e) => textblock_Click(s,e);
    textblock.PreviewMouseUp += MouseUpHandler;

    Canvas canvas = new Canvas();
    canvas.PreviewMouseUp += MouseUpHandler;
    canvas.Children.Add(textblock);
    canvas.Children.Add(circleImage);

    などと、textblockとcanvasにイベントハンドラを登録してみましたが、
    textblock.Click += (s,e) => textblock_Click(s,e);
    ではClickというイベントがないといわれました。
    canvas.PreviewMouseUp += MouseUpHandler;
    では、なにも処理されていないように見えます。

    (A)をクリックしたら、
    MessageBoxにAを表示する、というように処理したいです。

    2010年9月27日 6:33
  • なかむらさん。
    発言のタイミングで表示されてなかったのでお礼が遅れました。
    お手数おかけしました。同様に、Widthを設定して、うまくいきました。
    ありがとうございます。
    2010年9月27日 6:35