2009-05-28 23 views
1

私は、の代わりにCanvasを使用するようにItemsPanelTemplateを上書きするListBoxで作業しています。 ListBoxItemsにはDataTemplateがあり、コンバータを使用してキャンバス上の各ListBoxItemの外観と位置を定義します。 ListBoxがバインドされているコレクションにアイテムを追加すると、別のUIElementをキャンバスに追加できます。 ListBoxItemのコンバーターの外でこれを達成できますか?WPF:ItemsPanelTemplateがキャンバスであるListBoxにUIElementを追加しますか?

私のリソースセクションでは、このようなものです:

<Style TargetType="ListBox"> 
     <Setter Property="ItemsPanel"> 
      <Setter.Value> 
       <ItemsPanelTemplate> 
        <Canvas x:Key="cnvAwesome"> 

        </Canvas> 
       </ItemsPanelTemplate> 
      </Setter.Value> 
     </Setter> 
    </Style> 
    <Style TargetType="ListBoxItem"> 
     <Setter Property="Canvas.Left" Value="{Binding Path=Position.X}" /> 
     <Setter Property="Canvas.Top" Value="{Binding Path=Position.Y}" /> 
    </Style> 

そしてListBoxコントロール:

<ListBox x:Name="lstAwesome" ItemsSource="{Binding Source={StaticResource someCollection}}"/> 

そして、リストボックスがバインドされているコレクション:I場合は、だから、

public ObservableCollection<SomeType> someCollection {get; set; } 

ListBoxのlstAwesomeがバインドされているコレクションsomeCollectionに項目を追加するメソッドがあります。

private void AddItemToDataboundCollection(SomeType someItem) 
{ 
    someCollection.Add(someItem) 
    // I'd like to add a UIElement to the canvas that the ListBox uses to layout items here. 
} 

したがって、データバインドされたリストボックスによってItemsPanelに使用されているキャンバスにUIElementsを追加できますか?プログラムで、そのListBoxがバインドされているコレクションにアイテムを追加するときは?

私は大変感謝しています。あなたのItemTemplateがあなたの項目に基づいて変更したい場合、あなたはItemTemplateSelectorを設定しているItemTemplateへを決めることができ

<ListBox.ItemTemplate> 
    <DataTemplate> 
     <Rectangle Width="{Binding Width}" Height="{Binding Height}" /> 
    </DataTemplate> 
</ListBox.ItemTemplate> 

答えて

2

あなたの質問には、ListBoxCanvasに商品を追加するための準備が整っていると思います。私はちょうどあなたの質問のコードを使用して簡単なWPFテストアプリケーションをまとめ、それはちょうど働いた。 ObservableCollectionListBoxItemsSourceにバインドされたアイテムを追加すると、WPFはそのオブジェクトに対してListBoxItemを作成し、ListBoxItemのスタイルに基づいて、Canvasによって正しい場所にアイテムが描画されます。

上記のコードを正常に機能させることができませんでしたか?そういう場合は、あなたは何のエラーを受けたのですか、それとも期待どおりに動かなかったのでしょうか?

:もう一度質問を読んだ後、この混乱は、WPFバインディングがどのように動作するか誤解していると考えられます。コレクションをListBoxItemsSourceにバインドするときは、そのコレクションにアイテムを追加するだけです(コレクションにはINotifyCollectionChangedが実装されているとします)。ObservableCollectionの場合はこれを実行します。 WPFはそのインターフェイスによって提供されるイベントにサブスクライブし、リストに加えられた変更に基づいてListBoxItemsを作成/破棄します。

編集2:それはアイテムがコレクションに追加されたときに行が自動的に追加されるように、このためDataTemplateを使用する方がよいだろうが、私はあなたがの位置を得ることができるかどうかはわかりません以前に追加された項目は、行が正しい場所で開始するようにします。

Canvasをサブクラス化し、それをListBoxItemsPanelTemplateとして設定することもできます。私は、コントロールが追加されるたびに呼び出される関数をオーバーライドすることができると考えています。その関数では、以前に追加されたコントロール(あなたのCanvasサブクラスにキャッシュされます)の位置を取得してから、Canvasのコントロールにラインコントロールを直接追加することができます。これは、Canvasのコントロールの位置が変更できないと仮定します。可能であれば、おそらくオブジェクトのPropertyChangedイベントを購読し、それに応じて行を更新する必要があります。

編集3:あなたの要件のためにバインディングがオプションのようには見えないので、最も悪い選択肢は、子を直接追加することです。あなたはVisualTreeHelper.GetChild()を使用して、ビジュアルツリーを検索していることを行うことができます。

private T FindChild<T>(FrameworkElement parent, string name) 
    where T : FrameworkElement 
{ 
    FrameworkElement curObject = null; 
    T obj = default(T); 
    int count = VisualTreeHelper.GetChildrenCount(parent); 
    for(int i = 0; i < count; i++) 
    { 
     curObject = VisualTreeHelper.GetChild(parent, i) as FrameworkElement; 
     obj = curObject as T; 
     if(null != obj && obj.Name.Equals(name)) 
     { 
      break; 
     } 

     obj = FindChild<T>(curObject, name); 
     if(null != obj) 
     { 
      break; 
     } 
    } 

    return obj; 
} 

をこのようにそれを使用します。

Canvas canvas = FindChild<Canvas>(lstAwesome, "cnvAwesome"); 

このコードでは、再帰的に指定されたタイプの制御のためのparentのビジュアルツリーを検索し、名。 (VisualTreeHelper.GetChild()によって返されるものなので)FrameworkElementよりもDependencyObjectを使用する方が良いでしょうが、NameFrameworkElementでのみ定義されています。

ファンシーになりたい場合は、これを拡張方法にすることもできます。

+0

ちょっとアンディ、これをチェックしていただきありがとうございます。そして、はい、私のためにアイテムが正しく表示されます。私が質問しているのは、UIElementsをキャンバスに追加することができるかどうかです。*さらに、* ListItemsに追加します。私はcnvAwesomeへの参照を得ることができないようです(xaml参照) –

+0

Canvasに項目を追加するためにItemsPanelTemplateを変更することはできますか?そうでなければ、ListBoxItemごとにコントロールを1つ追加したいのであれば、idursunの方法に従うことをお勧めします。また、DataTemplateを変更して、アイテムをコレクションに追加するたびに追加のコントロールが自動的に追加されるようにします。 – Andy

+0

私はidursunの例に従いたいと思いますが、これらのUIElementsは手続き的に実行時に追加する必要があります。具体的には、ListBoxがバインドされているコレクションに項目が追加されたときです。 ListBoxが使用するItemsPanelのハンドルを取得できず、UIElementsを追加できません。私は本当に助けに感謝し、私は私の問題をより明確にすることができれば教えてください。 –

1

あなたは次のように、あなたのアイテムがItemTemplateを設定することで表示される方法を指定しますプログラムで使用することができます。

+0

この回答は私の質問に対処しているとは思わない。 ListBoxがそのItemsPanelにキャンバスを使用している場合、他のUIElementsをそのパネルにプログラムで追加するにはどうすればよいですか? –

+0

そして、あなたが本当に達成したいことについて具体的な例を挙げてください。 – idursun

+0

わかりやすく元の投稿を編集しました。不明な点があれば教えてください。ありがとう! –

関連する問題