7

文字列をプログラムで使用して、データフォームのxamlを作成しようとしています。コンボボックスを表示させることができます。しかし、文字列で「MouseLeftButtonUp」または「Loaded」イベントハンドラーを指定するコードを使用しようとすると、ページに入ると、ページが白くなります(目立ったエラーはありません)。以下の関連コードを参照してください。

     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;
4

4 に答える 4

1

1つの解決策はBeginningEdit、DataFormのイベントを処理し、それを使用してイベントハンドラーをComboBoxのMouseLeftButtonUpイベントにサブスクライブすることです。

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

次に、にx:Name="..."属性を追加しますComboBox。この名前を使用して、コンボボックスを取得します。

それが完了したら、次の2つのメソッドを追加します。これにより、必要な処理が実行されます。yourComboBoxNameコンボボックスに与えたものと置き換えx:Nameます。

    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;
            }
        }
    }

これら2つのメソッドの最初のメソッドをDataFormのBeginningEditイベントにサブスクライブします。

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

Dispatcher.BeginInvokeまた、行をメソッドへの直接呼び出しに置き換えてOnBeginEditみましたが、このアプローチは機能しないことがわかりました。イベントは正しく配線されていませんでした。繰り返しますが、理由はわかりません。

于 2013-01-17T21:23:41.950 に答える
1

XAMLに接続されたイベントハンドラーは、XAMLファイルに接続された分離コードで宣言する必要があります。ResourceDictionaryまたはXamlReader.Loadからロードされたものの場合、コードビハインドは存在できないため、XAMLでイベントハンドラーを設定することはできません。この制限を回避する最も簡単な方法は、文字列からテンプレートを作成せず、XAMLファイルの[リソース]セクションで宣言することです。これにより、次のように実行できます。

Resources["MyTemplate"] as DataTemplate

テンプレートを取得して、ここで行っているようにコードで割り当てるか、XAMLでStaticResourceを使用します。このコードに接続されている同じXAMLファイルにある限り、現在その中にあるイベントハンドラーは正常に機能するはずです。バインディングを使用するには、文字列の動的部分も変更する必要があります。

XamlReaderメソッドを使い続けたい場合は、解決すべき2つの問題があります。

  1. レンダリングされたテンプレート内でComboBoxインスタンスを見つけます
  2. テンプレートがレンダリングされるまで待って、ComboBoxを探します

ComboBoxを見つけるには、最初にテンプレートテキストでx:Name属性を指定する必要があります(現在そこにあるイベントコードを置き換えることができます)。次に、ビジュアルツリー内のアイテムを名前で検索できるようにする必要があります。これはかなり簡単で、これを行うための例をここで見つけることができます。

このコードを適切なタイミングで呼び出すには、OnApplyTemplateをオーバーライドする必要があります。これは、UserControlのようなものを使用している場合は残念ながら機能しません。または、別のトリックを使用して、すべてのコントロールがレンダリングされるまで実行されないようにします。コンストラクターに入れて、上からリンクされたfindメソッドを使用する完全な例を次に示します。

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");
});

あなたの場合、テンプレートがレンダリングされる前に編集状態に切り替わるのを待つ必要があるようです。その場合、イベントの接続を保留し、その状態が変更されたときに発生するデータフォーム上の他のイベントを見つける必要があります。 。

于 2013-01-17T21:30:06.590 に答える
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のコピーですが、イベント引数をコマンドに渡すように拡張されているため、同じことを行うことをお勧めします。

于 2013-01-22T12:03:13.593 に答える
0

XamlReader.LoadにeventHandlerをアタッチすることは許可されていません。したがって、この手法を使用して、eventHandlerを動的にアタッチします。

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

2-文字列をロードしますXamlReader.Load(str);

3-次に、そこからDataTemplateのコンテンツをロードします。を使用してGrid template = ((Grid)(dt.LoadContent()));

注:Gridこれがの親コントロールですDataTemplate

4-イベントハンドラーをアタッチする名前でコントロールを見つけます。 Button img = (Button)template.FindName("MyButtonInDataTemplate");

お役に立てば幸いです。

于 2015-05-01T09:40:53.077 に答える