2009-03-23 30 views
13

Tôi khá mới đối với WPF và cố gắng hiểu cách tốt nhất để mở rộng điều khiển ListBox. Là trải nghiệm học tập, tôi muốn xây dựng một số ListBoxListBoxItem s hiển thị CheckBox thay vì chỉ văn bản. Tôi nhận được rằng làm việc trong một thời trang cơ bản bằng cách sử dụng các ListBox.ItemTemplate, rõ ràng thiết lập tên của các thuộc tính tôi muốn databind đến. Một ví dụ là giá trị một ngàn chữ, như vậy ...Cách tạo ListBox.ItemTemplate có thể tái sử dụng/generic

Tôi đã có một đối tượng tùy chỉnh cho liên kết dữ liệu:

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

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

(. Tôi xây dựng một danh sách những người và thiết lập ListBox.ItemsSource vào danh sách đó) Và tôi XAML trông giống như sau:

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

Tác phẩm này. Nhưng tôi muốn làm cho mẫu này có thể tái sử dụng được, tức là tôi sẽ muốn liên kết với các đối tượng khác với các thuộc tính khác với "Đã kiểm tra" và "Tên hiển thị". Làm cách nào tôi có thể sửa đổi mẫu của mình sao cho tôi có thể biến nó thành tài nguyên, sử dụng lại nó trên nhiều trường hợp ListBox và cho từng trường hợp, ràng buộc IsCheckedContent với tên thuộc tính tùy ý?

+0

Tôi không nghĩ điều này là có thể. Để có được "kiểm tra" ràng buộc được linh hoạt, bạn sẽ phải phân lớp ListBox và thêm một CheckedMemberPath như DisplayMemberPath. Không thể làm điều này chỉ với một mẫu. –

+0

Đó là điều tôi sợ. Tôi đã bắt đầu tìm kiếm trong ListBox phân lớp, nhưng tôi vẫn đọc những thứ về cách các mẫu đáng kinh ngạc và cách bạn nên tránh các lớp con nếu nó hoàn toàn có thể thực hiện những gì bạn muốn với một khuôn mẫu. Tôi đoán đây có thể là một trường hợp tốt cho một phân lớp. Cảm ơn! –

Trả lời

14

Cách đơn giản nhất có lẽ là để đưa DataTemplate như một nguồn nơi nào đó trong ứng dụng của bạn với một TargetType của MyDataItem như thế này

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

Bạn sẽ có lẽ cũng phải bao gồm một xmlns để lắp ráp địa phương của bạn và tham khảo nó thông qua đó. Sau đó, bất cứ khi nào bạn sử dụng một ListBox (hoặc bất kỳ điều gì khác sử dụng một số MyDataItem trong một ContentPresenter hoặc ItemsPresenter), nó sẽ sử dụng DataTemplate này để hiển thị.

+0

Hấp dẫn! Tôi đã không nhận ra rằng bạn có thể áp dụng mẫu cho chính đối tượng dữ liệu đó. (BTW, tôi thấy rằng "TargetType" thực sự nên là "DataType" trên DataTemplate.) Tuy nhiên, nhược điểm của điều này là tôi sẽ phải xác định các mẫu cho từng loại nguồn dữ liệu ... mà tôi đang cố gắng tránh. –

+0

Cảm ơn, tôi đã sửa lỗi. Không có vấn đề gì bạn sẽ phải nói với giao diện người dùng mà trường là IsChecked và đó là nội dung. Bạn chỉ cần quyết định điều đó xảy ra ở đâu. Tôi có xu hướng thích nó ở cấp độ DataTemplate vì nó có xu hướng là nơi dễ nhất để duy trì trải nghiệm của tôi. –

16

Tạo DataTemplate làm tài nguyên và sau đó tham khảo nó bằng cách sử dụng thuộc tính ItemTemplate của ListBox. 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

Tôi nghĩ người hỏi đang hỏi làm thế nào để làm cho các tham số 'Đã kiểm tra' và 'DisplayName' được cung cấp cho khuôn mẫu, sao cho cùng một giao diện có thể được sử dụng ở nơi khác, nhưng có thể với một ràng buộc khác. –

+0

Hmm, vâng tôi thấy bạn đúng, tôi không chắc chắn điều đó là có thể, tôi sẽ chờ đợi một câu trả lời tốt hơn – MrTelly

+0

quyền của Jonathan; Tôi muốn có thể liên kết các loại đối tượng khác với cùng một mẫu. Cảm ơn bạn đã thử! –

2

Nếu bạn muốn một màn hình cách sau đó bạn có thể sử dụng một bộ chuyển đổi:

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

Sau đó XAML sẽ giống như thế này:

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

Đó mẫu dữ liệu bạn có thể làm giống như trên. Hai cách ràng buộc sẽ là một chút công bằng khó khăn hơn.

Tôi nghĩ rằng bạn nên làm cho các lớp cơ sở của mình triển khai giao diện ICheckedItem để hiển thị các thuộc tính chung mà bạn muốn các biểu dữ liệu liên kết với?

+0

Cách tiếp cận thú vị - cảm ơn! Tôi sẽ cần hai chiều ràng buộc, vì vậy tôi có lẽ sẽ tránh các tuyến đường chuyển đổi. Tuy nhiên, ICheckedItem mở ra những khả năng mới mà tôi đã không nghĩ tới. Giao diện có thể sẽ là con đường để đi. –

Các vấn đề liên quan