2009-03-23 12 views
13

私はWPFの新機能で、ListBoxコントロールを拡張する方法を理解しています。学習の経験として、ListBoxItemCheckBoxと表示されているListBoxを作成したかっただけです。 ListBox.ItemTemplateを使用して基本的な方法で作業しています。データバインドするプロパティの名前を明示的に設定します。ListBox.ItemTemplateを再利用/汎用にする方法

public class MyDataItem { 
    public bool Checked { get; set; } 
    public string DisplayName { get; set; } 

    public MyDataItem(bool isChecked, string displayName) { 
     Checked = isChecked; 
     DisplayName = displayName; 
    } 
} 

(私はそれらとそのリストにListBox.ItemsSourceセットのリストを作成します。)そして、私の例:私はデータバインディングのためのカスタムオブジェクトを持っている千個の言葉の価値があるので...

XAMLは次のようになります。

<ListBox Name="listBox1"> 
     <ListBox.ItemTemplate> 
      <DataTemplate> 
       <CheckBox IsChecked="{Binding Path=Checked}" Content="{Binding Path=DisplayName}" /> 
      </DataTemplate> 
     </ListBox.ItemTemplate> 
    </ListBox> 

これは機能します。しかし、私はこのテンプレートを再利用可能にしたい、つまり、 "Checked"と "DisplayName"以外のプロパティを持つ他のオブジェクトにバインドしたいと思うでしょう。テンプレートを変更してリソースを作り、複数のListBoxインスタンスで再利用できるようにするにはどうすればいいですか?また、インスタンスごとに任意のプロパティ名にIsCheckedContentをバインドしますか?

+0

私はこれが可能ではないと思います。 "Checked"バインディングを柔軟にするには、ListBoxをサブクラス化し、DisplayMemberPathのようなCheckedMemberPathを追加する必要があります。テンプレートだけではこれを行うことはできません。 –

+0

それは私が恐れていたものです。私はListBoxのサブクラス化について検討し始めましたが、信じられないほどのテンプレートがどのようなものか、サブクラスを避ける必要があるかについては、テンプレートを使ってできる限り達成することができます。私はこれがサブクラスのために良いケースかもしれないと思います。ありがとう! –

答えて

14

最も簡単な方法は、あなたはおそらく、あなたの地方議会にxmlnsを含める必要があります。この

<DataTemplate DataType="{x:Type MyDataItem}"> 
    <CheckBox IsChecked="{Binding Path=Checked}" Content="{Binding Path=DisplayName}" /> 
</DataTemplate> 

ようMyDataItemTargetTypeと、アプリケーション内のどこかにDataTemplateなどのリソースを置くために、おそらくですそれを通してそれを参照してください。 ListBox(またはContentPresenterまたはItemsPresenterMyDataItemを使用するもの)を使用する場合は、このDataTemplateを使用して表示します。

+0

魅力的!私はあなたがデータオブジェクト自体にテンプレートを適用できることに気づいていませんでした。 (BTT、私は "TargetType"は実際にはDataTemplateの "DataType"でなければならないことに気付きました)。しかし、これの欠点は、私が避けようとしていたデータソースの種類ごとにテンプレートを定義しなければならないことです。 –

+0

ありがとう、私はエラーを修正しました。どのフィールドがIsCheckedで、どのフィールドがコンテンツであるかをUIに伝える必要はありません。あなたはどこでそれが起こるかを決めなければなりません。私はDataTemplateレベルでそれを好む傾向があります。なぜなら、私の経験で維持するのが最も簡単な場所である傾向があるからです。 –

16

DataTemplateをリソースとして作成し、ListBoxのItemTemplateプロパティを使用して参照します。 MSDN has a good example

<Windows.Resources> 
    <DataTemplate x:Key="yourTemplate"> 
    <CheckBox IsChecked="{Binding Path=Checked}" Content="{Binding Path=DisplayName}" /> 
    </DataTemplate> 
... 
</Windows.Resources> 

... 
<ListBox Name="listBox1" 
     ItemTemplate="{StaticResource yourTemplate}"/> 
+0

私は質問者がテンプレートに提供された 'Checked'と 'DisplayName'パラメータをどのように作成するかを尋ねているので、同じ外観を別の場所で使うことができますが、 –

+0

うーん、あなたが正しいと思うよ、私はそれが可能であるとは確信していない、私はより良い答えを待つよ – MrTelly

+0

ジョナサンの権利;他のタイプのオブジェクトを同じテンプレートにバインドできるようにしたいと思います。しかし、試してくれてありがとう! –

2

あなたは一方通行表示を望んでいたなら、あなたは、コンバータを使用することができます。

class ListConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     return ((IList<MyDataItem>)value).Select(i => new { Checked = i.Checked2, DisplayName = i.DisplayName2 }); 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 

その後XAMLは、このようなものになります。データはあなたが作ることができ、そのテンプレートを

<Window.Resources> 
    <this:ListConverter x:Key="ListConverter" /> 
</Window.Resources> 
<ListBox ItemsSource="{Binding Path=Items, Converter={StaticResource ListConverter}}"> 
    <ListBox.ItemTemplate> 
     <DataTemplate> 
      <CheckBox IsChecked="{Binding Path=Checked, Mode=OneWay}" Content="{Binding Path=DisplayName, Mode=OneWay}" /> 
     </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 

を上記のような一般的な双方向バインディングはかなり難しいでしょう。

あなたは基本クラスにデータ型をバインドする汎用プロパティを公開するICheckedItemインターフェイスを実装する方が良いと思いますか?

+0

興味深いアプローチ - ありがとう!私は双方向バインディングが必要なので、私はおそらくコンバータのルートを避けるでしょう。しかし、ICheckedItemは私が考えていなかった新しい可能性を開きます。インターフェイスは、最終的に行く方法になるかもしれません。 –

関連する問題