2010-02-21 19 views
16

Có thể sử dụng bộ chuyển đổi giá trị mà không cần phải định nghĩa chúng trước đó làm tài nguyên không?Sử dụng bộ chuyển đổi giá trị trong WPF mà không cần phải xác định chúng là tài nguyên đầu tiên

Ngay bây giờ tôi có

<Window.Resources> 
    <local:TrivialFormatter x:Key="trivialFormatter" /> 
</Window.Resources> 

<Button Width="{Binding Width, ElementName=textBox1, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource trivialFormatter}}" Height="50"> 

Nó sẽ không được có thể là thay vì phải khai báo tài nguyên trivialFormatter trong Window.Resources, tôi trực tiếp có thể tham khảo nó từ Chiều rộng của nút? Một cái gì đó như

Converter = {local:TrivialFormatter} 

Cảm ơn

Trả lời

22

Trong trường hợp của singleton kiểu IValueConverter s (ví dụ như họ không cần bất kỳ nhà nước từ trường hợp ràng buộc hiện tại) tôi sử dụng bộ chuyển đổi tĩnh, ví dụ:

Converter={x:Static SomeNamespace:SomeConverter.Instance} 

Ngoài ra còn có một bài tuyệt vời bởi Dr. WPF về cách sử dụng một phần mở rộng đánh dấu để làm cho nó sạch hơn nội tuyến here.

+0

Bí quyết tuyệt vời với tiện ích mở rộng đánh dấu! Tuy nhiên, trong ví dụ đầu tiên của bạn, bạn không cần phải tạo một phiên bản tĩnh của VC, ví dụ: '{x: Tĩnh cục bộ: SomeConverter.Instance}'? – itowlson

+0

Đây là một gợi ý rất tốt. Khi tạo các trình biến đổi giá trị của riêng bạn, bạn nên luôn yêu cầu chúng chấp nhận một ConverterParameter thay vì có các đặc tính cá thể để bạn có thể sử dụng một cá thể singleton như thế này. Đó là SO dễ dàng hơn nhiều so với việc sử dụng tài nguyên. Tôi thường gọi cho tôi một cái gì đó như {x: tĩnh địa phương: InvertedBooleanConverter.Default} hoặc một cái gì đó. – Josh

+0

@ itowlson - vâng trong trường hợp - Tôi đã chỉnh sửa câu trả lời của mình. Thx cho bắt. – micahtan

2

Tôi không biết một cách để làm điều này theo cách của bạn được nêu, nhưng tôi chỉ cố gắng này như một mẫu và nó làm việc. Trong tệp App.xaml.cs của bạn, bạn có thể tạo phương thức sử dụng phản chiếu để tải trình chuyển đổi.

private void Application_Startup(object sender, StartupEventArgs e) 
{ 
    LoadConverters(); 
} 

private void LoadConverters() 
{ 
    foreach(var t in Assembly.GetExecutingAssembly().GetTypes()) 
    { 
     if (t.GetInterfaces().Any(i => i.Name == "IValueConverter")) 
     { 
      Resources.Add(t.Name, Activator.CreateInstance(t)); 
     } 
    } 
} 

Sau đó, bạn có thể sử dụng trình chuyển đổi như thế này, một nửa ở đó tôi đoán.

<Button Width="{Binding Width, Converter={StaticResource TrivialFormatter}}" /> 

Vấn đề với cách tiếp cận bạn đề xuất là trình phân tích cú pháp Xaml không biết khi nào và bao nhiêu trình tạo của bạn tạo. Tạo tài nguyên dưới dạng tài nguyên chỉ đảm bảo một phiên bản.

+0

Trên một chủ đề tương tự, bạn có thể tạo tiện ích đánh dấu trả về một thể hiện của loại đối số của nó. Sau đó, bạn có thể viết 'Converter = {local: InstanceOf {x: Type local: TrivialFormatter}}'. Như bạn lưu ý, mặc dù, điều này sẽ dẫn đến một instantiation riêng biệt cho mỗi ràng buộc, đó là khả năng lãng phí (đặc biệt là nếu được sử dụng trong ItemTemplate cho một ItemsControl lớn). – itowlson

6

Về mặt kỹ thuật tôi tin rằng bạn có thể làm điều này, nhưng XAML là khủng khiếp như vậy mà nó sẽ làm cho "rất nhiều tài nguyên tầm thường" cách tiếp cận trông giống như một thiên đường của sự đơn giản và rõ ràng bằng cách so sánh:

<Button Height="50"> 
    <Button.Width> 
    <Binding Path="Width" ElementName="textBox1" UpdateSourceTrigger="PropertyChanged"> 
     <Binding.Converter> 
     <local:TrivialFormatter /> 
     </Binding.Converter> 
    </Binding> 
    </Button.Width> 
</Button> 

Tôi có không thử nghiệm điều này bởi vì ngay cả đọc nó làm cho đôi mắt của tôi nước ...

+5

Đây là một cách hoàn toàn hợp lệ để làm việc đó. Nhưng như bạn đã lưu ý sự verbosity của XAML giống như Ark of the Covenant và chỉ nhìn vào nó sẽ nuốt chửng linh hồn bạn. – Josh

+0

Cách tiếp cận này có thể hữu ích trong trường hợp bạn muốn đặt một số thuộc tính trên một phiên bản cụ thể của trình biến đổi, như '' – chviLadislav

5

Tôi chắc chắn sẽ xem xét đề xuất của Micah liên quan đến việc sử dụng một trường hợp đơn lẻ tĩnh của công cụ chuyển đổi của bạn. Nhưng một điều cần xem xét là nếu bạn đang sử dụng một mẫu trình bày riêng biệt như MVVM, bạn thường có thể tránh yêu cầu đối với trình chuyển đổi giá trị bằng cách thực hiện chuyển đổi trong ViewModel.

Có rất nhiều lý do bạn có thể muốn thực hiện việc này.

Đối với một, nó dễ kiểm tra hơn nhiều. Kiểm tra đơn vị của bạn có thể chắc chắn rằng bất cứ điều gì sắp ra khỏi ViewModel là những gì sẽ được hiển thị bởi giao diện người dùng. Bạn có thể tưởng tượng thử nghiệm một yêu cầu rằng giá trị đồng USD phải tuân theo định dạng tiền tệ các nền văn hóa hiện tại, hai số thập phân phải được sử dụng, vv

Một lý do chính đáng là trường hợp ngoại lệ trong bộ chuyển đổi giá trị sẽ không được coi là lỗi xác nhận có thể được một nỗi đau lớn trong mông trong Silverlight.Ngay cả khi bạn đặt ValidatesOnExceptions thành true trong ràng buộc, nếu trình biến đổi giá trị của bạn ném một ngoại lệ, Silverlight sẽ chỉ cho phép nó truyền bá. Tuy nhiên, nếu bạn sử dụng ViewModel để thực hiện chuyển đổi, một ngoại lệ sẽ được coi là lỗi xác thực.

Nhược điểm là bạn mất một số "khả năng tái sử dụng" của bộ chuyển đổi giá trị mục đích chung.

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