2009-12-13 37 views
8

tôi có phần mở rộng đánh dấu nàyXác định DataTemplate.DataType với một kiểu tùy chỉnh mở rộng

public class NullableExtension : TypeExtension 
{ 
    public NullableExtension() { 
    } 

    public NullableExtension(string type) 
     : base(type) { 
    } 

    public NullableExtension(Type type) 
     : base(type) { 
    } 

    public override object ProvideValue(IServiceProvider serviceProvider) { 
     Type basis = (Type)base.ProvideValue(serviceProvider); 
     return typeof(Nullable<>).MakeGenericType(basis); 
    } 
} 

được thiết kế để cung cấp một phiên bản nullable của một số loại khác. Nó hoạt động như mong đợi khi được sử dụng trong XAML "bình thường". Ví dụ: như trong

<SomeControl DataContext="{My:Nullable System:Int32}"/> 

(giả định rằng My là không gian tên XML được định nghĩa cho không gian tên C# đang giữ phần mở rộng và tương tự cho Hệ thống). Ngữ cảnh dữ liệu cho điều khiển được đặt thành System.Type cho Nullable<int> như tôi mong đợi.

Tuy nhiên, khi tôi sử dụng phần mở rộng này để thử và thiết lập các DataType tài sản của một DataTemplate như

<DataTemplate DataType="{My:Nullable System:Int32}"> 
    <TextBlock ... /> 
</DataTemplate> 

tôi đã nói, bởi trình biên dịch, mà

Một chìa khóa cho một cuốn từ điển không thể thuộc loại 'System.Windows.Controls.Primitives.TextBlock'. Chỉ String, TypeExtension, và StaticExtension được hỗ trợ. "

" Không constructor cho loại 'NullableExtension' có 1 tham số.

Có ai biết tại sao chỉ ba phương thức đó (và thậm chí không phải lớp con của TypeExtension, như của tôi) được phép không? Điều gì là đặc biệt về việc xử lý XAML tại thời điểm đó? Và có cách nào khác để thực hiện điều này (lựa chọn mẫu dữ liệu dựa trên các loại có thể rỗng) mà không cần sử dụng đến một số DataTemplateSelector?

Trả lời

11

Tôi thực sự có câu hỏi của bạn, và đây là những gì tôi tìm thấy.

Q: Tại sao chỉ có những ba (String, TypeExtension, và StaticExtension) được phép?

A: Theo thiết kế. Nếu bạn có thể viết bất kỳ phần mở rộng đánh dấu tùy chỉnh nào được sử dụng làm khóa trong từ điển, thì những tác dụng phụ nào sẽ được giới thiệu? Hãy xem xét bạn có Binding như là một giá trị của DataType ... Tôi khá chắc chắn bạn có thể thêm tá vấn đề liên quan đến từ điển phím năng động.

Q: Điều gì đặc biệt về việc xử lý XAML tại điểm đó?

A. Vào thời điểm đó, bạn đã tạo BAML. Vấn đề xuất phát từ lớp nội bộ BamlRecordWriter, nhưng thông báo không mô tả sự cố thực tế. Khi bạn chỉ định phần mở rộng đánh dấu tùy chỉnh làm Kiểu dữ liệu, nó cần một số con của DataTemplate và kiểm tra nếu nó có thể gán từ chuỗi, TypeExtension hoặc StaticExtension (xem BamlRecordWriter.WriteElementStart() chức năng). Thật.Không phải phần mở rộng của bạn (có thể gán cho TypeExtension), nhưng con đầu tiên (không thể gán). Bây giờ bạn có điều này lạ "không thể là loại" điều. Mặc dù nó trông giống như lỗi của BamlRecordWriter, tôi nghĩ họ đã cố tình để nó. Cho đến khi nó không cho phép bạn sử dụng tiện ích đánh dấu tùy chỉnh làm giá trị DataType, ai quan tâm đến thông báo lỗi?

Q: Có một cách khác để thực hiện điều này (mẫu lựa chọn dữ liệu dựa trên các loại mà bạn có thể nullable) mà không cần đến một DataTemplateSelector?

A: Có, loại. Trước hết, bạn có thể có TypeExtension tiêu chuẩn làm tất cả công việc dơ bẩn cho bạn:

<DataTemplate DataType="{x:Type TypeName=System:Nullable`1[[System.Int32]]}"> 
</DataTemplate> 

Nhưng trong hầu hết các trường hợp (nếu không phải lúc nào) bạn sẽ không thấy kết quả khuôn mẫu. Tại sao? Bây giờ nói đến các quy tắc boxing cho các loại nullable. Việc đánh boxing một loại giá trị null không null sẽ tự động đánh giá kiểu giá trị của nó, không phải là System.Nullable. Do đó, trình chọn mẫu mặc định sẽ tìm DataTemplate với DataType là T không phải là Nullable<T>.

Tôi có thể không hiểu chính xác vấn đề bạn đang cố gắng giải quyết với phần mở rộng nullable, nhưng bạn có thể muốn bọc null vào loại ref của riêng bạn, viết một DataTemplate cho wrapper và sử dụng DataTemplate.Triggers, để chọn nội dung xuất hiện. Vâng, điều này giống như bộ chọn mẫu dữ liệu được tạo lại:) ...

NB: Tôi không phải là một anh chàng MS và kết quả của tôi dựa trên Reflector và trải nghiệm của riêng tôi (không lớn bằng tôi muốn là alt text http://www.kolobok.us/smiles/standart/blush2.gif). Trong mọi trường hợp, hy vọng tôi có thể giúp :).

Cheers

+0

Cảm ơn. Tôi nhận ra nó có thể nguy hiểm nhưng tôi nghĩ rằng nó sẽ có thể xác nhận loại giá trị được gán cho DataType, trên thực tế, một System.Type. Tôi không cố gắng gán bất kỳ giá trị tùy ý nào cho DataType, chỉ là một Loại. Thú vị về trình phân tích cú pháp BAML. Đối với vấn đề boxing, đó là một điểm tốt, mặc dù trong trường hợp tôi đã có tôi sẽ cung cấp một cách rõ ràng Nullable thay vì một giá trị đóng hộp và có giàn giáo khác tại chỗ để làm cho rằng "làm điều đúng" cho nhu cầu của tôi. Có vẻ như tôi sẽ phải tiếp tục giải quyết sự cố. Cảm ơn đã giúp đỡ. –

+0

Rất tiếc, tôi luôn quên rằng các nhận xét không giữ thêm dòng mới tại đây. Xin lỗi ở trên là định dạng quá icky. –

+1

Mọi thứ rõ ràng đã thay đổi kể từ khi nó được viết, và trong khi nó trông giống như 'DataType =" {x: Type TypeName = System: Nullable \ '1 [[System.Int32]]}" 'sẽ hoạt động, vào tháng 8 năm 2013, dưới. NET 4.0, nó không. Cách duy nhất tôi tìm thấy để giải quyết vấn đề này là sử dụng một số loại MarkupExtension. – Dan

1

Cú pháp

DataType="{x:Type TypeName=System:Nullable`1[[System.Int32]]}"> 

dường như không làm việc cho người sử dụng định nghĩa loại :(

Trên thực tế một cách khác là tạo ra một cơ sở loại không chung chung. Đặt đầu tiên mẫu dữ liệu cho loại đó và liên kết ContentPresenter.Content với thuộc tính chứa đối tượng T. Sau đó, tạo các mẫu dữ liệu khác cho bất cứ điều gì T.

1

điều này sẽ hoạt động ...

<DataTemplate DataType="{x:Type System:Nullable`1[System.Int32]}"> 
</DataTemplate> 
+0

Để viết một câu trả lời tốt hơn, bạn nên cung cấp một số ngữ cảnh với giải pháp (tại sao nó hoạt động? Bạn đã sử dụng nguồn nào?) – Dhara

2

Tôi đã tìm thấy cách giải quyết khó chịu cho việc này. Vì lý do gì đó, @Anvaka là đúng: thuộc tính DataType sẽ không cho phép bạn sử dụng MarkupExtension tùy chỉnh. Nhưng nó S allow cho phép bạn sử dụng một StaticResource của MarkupExtension tùy chỉnh.

Lấy MarkupExtension của bạn, thêm một hàm tạo mặc định công khai vào nó. Sau đó tạo một thể hiện của phần mở rộng của bạn trong các tài nguyên, thiết lập các thuộc tính trực tiếp. Boom, nó mất nó. Phần dưới đây tương tự như những gì bạn cần làm

<My:Nullable x:Key="Foo" Type="{x:Type System:Int32}"/> 
<DataTemplate DataType="{StaticResource Foo}"> 
    <TextBlock ... /> 
</DataTemplate> 
Các vấn đề liên quan