2013-01-07 10 views
7

文字列を使用してデータフォームのxamlをプログラムで作成しようとしています。私はコンボボックスを表示させることができます。しかし、文字列に "MouseLeftButtonUp"または "Loaded"イベントハンドラを指定するコードを使用しようとすると、それに入るとページは白く(顕著なエラーなしに)変わります。下記の関連コードをご覧ください。Silverlightのdataformのデータテンプレートとして文字列を使用する場合のイベントハンドラ

 StringBuilder editTemplate = new StringBuilder(""); 
    editTemplate.Append("<DataTemplate "); 
    editTemplate.Append("xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' "); 
    editTemplate.Append("xmlns:toolkit='http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit' "); 
    editTemplate.Append("xmlns:navigation='clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation' "); 
    editTemplate.Append("xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' >"); 
    editTemplate.Append("<StackPanel>"); 
    editTemplate.Append(@" <toolkit:DataField Label='" + GetFieldWithoutNumber(theInfo, theDataContext) + "'>"); 
    /* Won't Work */ editTemplate.Append(@" <ComboBox MouseLeftButtonUp='ComboBox_MouseLeftButtonUp' />"); 
    /* Will Work */ editTemplate.Append(@" <ComboBox />"); 
    editTemplate.Append(@" </toolkit:DataField>"); 
    editTemplate.Append("</StackPanel></DataTemplate>"); 
    dynamicDataForm.EditTemplate = XamlReader.Load(editTemplate.ToString()) as DataTemplate; 
+1

これは私を驚かせるものではありません。あなたが行うべきことは、データ・テンプレートを作成した後にイベント・ハンドラをプログラムでフックすることです。 – slugster

+0

@slugsterお願いします...どうすればいいですか?ちょうどそれに名前をつけますか? – Kulingar

答えて

1

XAMLに接続されたイベントハンドラは、XAMLファイルに接続されたコードビハインドで宣言する必要があります。 ResourceDictionaryやXamlReader.Loadからロードされたものの場合は、コードビハインドができないため、XAMLにイベントハンドラを設定することはできません。この制限を回避する最も簡単な方法は、文字列からテンプレートを構築し、ちょうどあなたが、その後のように行うことができますあなたのXAMLファイルのリソースセクションでそれを宣言しないことであろう:テンプレートを取得するために

Resources["MyTemplate"] as DataTemplate

とここでやっているようにコードで割り当てるか、XAMLでStaticResourceを使用してください。このコードに接続された同じXAMLファイルにとどまっている限り、あなたが現在持っているイベントハンドラは正常に動作するはずです。文字列の動的部分も、Bindingsを使用するように変更する必要があります。

XamlReaderメソッドを使用する場合は、解決する2つの問題があります。

  1. テンプレートは、あなたが最初にそれをXを与える必要がコンボボックス見つけるにはコンボボックス

を探すためにレンダリングされるまで、レンダリングされたテンプレート

  • 待ちの内側にComboBoxインスタンスを見つけます。Name属性でのテンプレートテキスト(現在のイベントコードを置き換えることができます)。次に、ビジュアルツリー内のアイテムを名前で見つける必要があります。これはかなり簡単で、そのためにexample hereが見つかります。

    このコードを適切なタイミングで呼び出すには、OnApplyTemplateをオーバーライドする必要があります。残念なことに、UserControlのようなものではうまくいきません。また、すべてのコントロールがレンダリングされるまで別のトリックを使用して実行しないでください。それはその場合にレンダリングする前に、編集状態に切り替えることを待つ必要がありますあなたの場合、それはあなたのテンプレートのように見えるでは

    DataTemplate template = Resources["MyTemplate"] as DataTemplate; 
    dynamicDataForm.ContentTemplate = template; 
    
    Dispatcher.BeginInvoke(() => 
    { 
        ComboBox button = FindVisualChildByName<ComboBox>(this, "MyControl"); 
        if (button != null) 
         button.MouseLeftButtonUp += (s, _) => MessageBox.Show("Click"); 
    }); 
    

    :ここでは、コンストラクタに行くと、上記からリンクされているfindメソッドを使用して可能性があり、完全な例ですイベントを接続するのを延期し、その状態が変更されたときに起こる他のイベントをデータフォーム上で見つける必要があります。

  • 1

    一つの解決策は、データフォームのBeginningEditイベントを処理し、コンボボックスのMouseLeftButtonUpイベントにイベントハンドラを購読することを使用することです。

    これを行うには、isEventWiredUpという名前のプライベートフィールドをコードビハインドに追加します。このフィールドを使用して、イベントに登録しているかどうかを追跡し、イベントが複数回サブスクライブされないようにします。

    次に、ComboBoxx:Name="..."という属性を追加します。私たちはこの名前を使ってコンボボックスに入ります。

    これが完了したら、になります。次の2つの方法を追加します。あなたのコンボボックスに与えたx:NameyourComboBoxNameを置き換えます

    private void dynamicDataForm_BeginningEdit(object sender, CancelEventArgs e) 
        { 
         Dispatcher.BeginInvoke(OnBeginEdit); 
        } 
    
        private void OnBeginEdit() 
        { 
         if (!isEventWiredUp) 
         { 
          var combobox = dynamicDataForm.FindNameInContent("yourComboBoxName") as ComboBox; 
          if (combobox != null) 
          { 
           combobox.MouseLeftButtonUp += combobox_MouseLeftButtonUp; 
           isEventWiredUp = true; 
          } 
         } 
        } 
    

    は、データフォームのBeginningEditイベントにこれらの2つの方法の最初のを購読します。

    ComboBoxでMouseLeftButtonUpイベントを発生させることができなかったことを認めなければなりません。なぜこのようなことが起こるのか分かりませんが、XAMLを構築する方法が原因で起こることとは対照的に、ComboBoxの一般的な問題と思われます。私はComboBoxのSelectionChangedイベントのイベントハンドラを取得することができました。

    OnBeginEditメソッドへの直接呼び出しでDispatcher.BeginInvoke行を置き換えようとしましたが、この方法は機能しませんでした。イベントは正しく配線されていませんでした。もう一度、なぜ私は確信していません。

    +0

    13kのユーザーが何か起きているのか分からないと答えた場合、私の正気を正当化するので、私は幸せになれます。 ;)あなたのご意見ありがとうございます、私はあなたとルークの提案を見ています。まもなくお知らせいたします。 :)しかし、あなたのことは簡単だと思われます。 – Kulingar

    0

    直接ではなく、イベントをフックアップしようとしている、あなたはあなたのイベント

    例えばをバインドするために対話を使用することができます

    ... 
    editTemplate.Append("xmlns:i='clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity' "); 
    ... 
    editTemplate.Append(@" 
    <ComboBox> 
    <i:Interaction.Triggers> 
        <i:EventTrigger EventName='MouseLeftButtonUp'> 
    
         <i:InvokeCommandAction Command='{Binding DataContext.YourCommand,                     
          RelativeSource={RelativeSource AncestorType=XXX}}' 
          CommandParameter='{Binding}'/> 
    
        </i:EventTrigger> 
    </i:Interaction.Triggers> 
    </ComboBox>"); 
    

    ハンドラが定義されているコンテキストに到達するには、祖先バインディングを使用する必要があります。 InvokeCommandActionのカスタム実装を使用します。基本的にはSystem.Windows.Interactivity.InvokeCommandActionのコピーですが、イベントargsをコマンドに渡すように拡張されていれば、同じことをしたいかもしれません。

    0

    XamlReader.Loadは、その中にeventHandlerを添付することはできません。 この手法を使用して、イベントハンドラを動的にアタッチしてください。

    1 eventHandlersを使用せずにXaml文字列を記述します。ただし、これらのコントロールのNameプロパティを記述します。

    2-そしてそれからのDataTemplateのコンテンツをロードXamlReader.Load(str);

    3-文字列を読み込み。使用するGrid template = ((Grid)(dt.LoadContent()));

    注:Gridは、DataTemplateの親コントロールです。

    4-イベントハンドラを添付する名前でコントロールを検索します。 Button img = (Button)template.FindName("MyButtonInDataTemplate");

    私はそれが役に立ちそうです。

    関連する問題