none
WPF XamlReaderで追加するViewboxに、MouseLeftButtonDownをバインドさせたい RRS feed

  • 質問

  • VisualStudio2010RC, WPF4.0で開発しています。

    MainWindow.xaml において Canvas (Name="canvas1")を配置しています。
    ここで、ボタン(Name="button1)がクリックされたとき、canvas1に
    Viewboxを追加したいです。このとき、追加されたViewboxをクリックすると、
    "Clickされました"とMessageBoxを表示させたいです。

    ■出来ていること
    ・ボタンをクリックすると、Viewboxをcanvas1内に配置する。

    以下のように実現しています。

    private void button1_Click(object sender, RoutedEventArgs e) {
      try {
          canvas1.ChildrenAdd((UIElement)XamlReader.Parse(getXAMLText()));
      } catch (Exception ex) {
          MessageBox.Show(ex.ToString());
      }
    }

    private string getXAMLText() {
      string head = <Canvas xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" Height=\"201\" HorizontalAlignment=\"Stretch\" Name=\"canvas1\" VerticalAlignment=\"Stretch\" Background=\"#FFAACBF2\" Margin=\"0,0,0,0\">";
      string tail = "</Canvas>";
      string str = "<Viewbox Width=\"50\" Height=\"50\"><Canvas 省略します>省略します</Canvas></Viewbox>";

      return (head + str + tail);
    }

    ■できないこと
    ・上の Viewbox をクリックすると "Clickされました" と画面出力
    ・上のコードに加えて、以下を記述しましたが駄目でした。エラーコードは後述します。

    private void Viewbox_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
      MessageBox.Show("Click");
    }

    // 変更点のみ
      string str = "<Viewbox Width=\"50\" Height=\"50\" MouseLeftButtonDown=\"Viewbox_MouseLeftButtonDown\">省略します

    ■エラーコード
    ・button1をクリックすると、以下のエラーをキャッチします。

    System.Windows.Markup.XamlParseException: 'Failed to create a 'MouseLeftButtonDown' from the text 'Viewbox MouseLeftButtonDown'.' Line number
    '1' and line position '482'. ---> System.ArgumentException: ターゲットメソッドにバインドしようとしてエラーが発生しました。
    //以下省略します

    ===================
    このエラーが生じる原因、および解決方法を調べましたが分かりませんでした。
    分かる方がおりましたら、ご教授お願いいたします。

    2010年3月29日 10:07

回答

  • VisualStudio2010RC, WPF4.0の環境が用意できなかったので、VisualStudio2008Pro, WPF3.5での話になってしまうことを最初にお断りさせていただきます。

     

    「XamlReaderを使用して」という前提条件がなければ動的生成したコントロールにイベントハンドラを追加することは簡単にできるかと思いますが、

    今回は「XamlReaderを使用して」とのことですので、1つ案があります。

    ただ、XamlReaderを使用しなければならないということを鑑みますと、あまり現実的ではないかもしれません。

     

    前置きが長くなりましたが、具体的には、

    MainWindow.xamlで宣言しているCanvas(Name="canvas1")のリソースとして、ViewboxのStyleを宣言し、その中でEventSetterを用いるという方法です。

        <Canvas
            x:Name="canvas1">
            <Canvas.Resources>
                <Style TargetType="{x:Type Viewbox}">
                    <EventSetter Event="MouseLeftButtonDown" Handler="Viewbox_MouseLeftButtonDown"/>
                </Style>
            </Canvas.Resources>
    
    
        </Canvas>

     

     

    一応これで動作するところまでは確認しましたが、

    前置きしたように、XamlReaderを使用しなければならない背景をよく理解しておりませんので的外れかもしれません。


    ※私が試したときは省略された部分を用意するのが面倒でしたのでstrを下記のように変更しました。

    string str = "<Viewbox Width=\"50\" Height=\"50\"><TextBlock Text=\"123\"></TextBlock></Viewbox>";

    2010年3月29日 17:02

すべての返信

  • 調べてみたところ、動的に読み込まれるコントロールのイベント ハンドラを、XAML では直接指定できないようです。

     

    ViewBoxにNameを指定しておき、XamlReaderで読み込んだあとにコードでイベントハンドラを登録する方法が使えるのではないでしょうか?

     

    参考URL:http://msdn.microsoft.com/ja-jp/magazine/cc947916.aspx



    なかむら(http://d.hatena.ne.jp/griefworker)
    2010年3月29日 10:43
  • ありがとうございます。

    いただいた情報をもとに、更に調べてみます。

    2010年3月29日 13:08
  • VisualStudio2010RC, WPF4.0の環境が用意できなかったので、VisualStudio2008Pro, WPF3.5での話になってしまうことを最初にお断りさせていただきます。

     

    「XamlReaderを使用して」という前提条件がなければ動的生成したコントロールにイベントハンドラを追加することは簡単にできるかと思いますが、

    今回は「XamlReaderを使用して」とのことですので、1つ案があります。

    ただ、XamlReaderを使用しなければならないということを鑑みますと、あまり現実的ではないかもしれません。

     

    前置きが長くなりましたが、具体的には、

    MainWindow.xamlで宣言しているCanvas(Name="canvas1")のリソースとして、ViewboxのStyleを宣言し、その中でEventSetterを用いるという方法です。

        <Canvas
            x:Name="canvas1">
            <Canvas.Resources>
                <Style TargetType="{x:Type Viewbox}">
                    <EventSetter Event="MouseLeftButtonDown" Handler="Viewbox_MouseLeftButtonDown"/>
                </Style>
            </Canvas.Resources>
    
    
        </Canvas>

     

     

    一応これで動作するところまでは確認しましたが、

    前置きしたように、XamlReaderを使用しなければならない背景をよく理解しておりませんので的外れかもしれません。


    ※私が試したときは省略された部分を用意するのが面倒でしたのでstrを下記のように変更しました。

    string str = "<Viewbox Width=\"50\" Height=\"50\"><TextBlock Text=\"123\"></TextBlock></Viewbox>";

    2010年3月29日 17:02
  • ありがとうございます。

    書いていただいた方法で、やりたいことが実現できました。

     

    なお、XamlReaderを使用する理由は、

    ・Illustratorファイルから出力したXAML(パス情報など)を、ボタンを押すことでCanvasに配置したいから

    ・(パス情報などの)XAMLを *.cs のコードから読み込むには、XamlReaderが適当だと感じたから

    です。XamlReaderを使用しなくても、もっと簡単に実現できますでしょうか?

     

    また、なかむらさんに提示していただいた情報は、私には難解なもので

    まだまだ勉強が必要だと痛感しました。

    やりたいことは実現できましたが、こちらも並行して勉強していきます。

    2010年3月30日 12:02
  • Illustratorから出力したXAMLが、アプリケーション実行中に変更できなくても良いのであれば、

    ResourceDictionaryとしてXAMLファイルを出力してもらい、

    C#のコード上でそのResourceDictionaryをXamlLoaderで読み込んで、リソース名を指定して取得したリソースを、動的生成したCanvasなどに追加するというのはいかがでしょうか。

    もしくは、そのリソースを使用するユーザコントロールを作成して、そのコントロールを動的に生成するというのも考えられます。

    いずれにしても、stringで用意したXAMLを読ませるとかしなくてすむので使い勝手は上がると思います。

    (ちょっと違いますがこんな感じのことを以前した気がします…。)

     

    アプリケーション実行中に変更できなければならないのであれば、動的生成した文字列をXamlLoaderに注入するのが良いと思います。

    2010年3月30日 15:50