2010-04-30 34 views
5

Chúng tôi đang sử dụng Microsoft Unity và dependency injection và vì vậy chúng tôi có parametrised constructor cho usercontrol. Làm thế nào để tiêm phụ thuộc vào usercontrol sử dụng XAML?Wpf usercontrol với constructor parameterised

Tôi đã thêm usercontrol vào XAML như dưới đây.

xmlns:usrRefundArrivalProcessor="Ttl.Refunds.Wpf.Dashboad.Application.Usercontrols;assembly=Ttl.Refunds.Wpf.Dashboad.Application" 

Trả lời

10

Chèn phụ thuộc không hàm ý các hàm tạo tham số. Trong thực tế, nếu bạn nhìn vào các mẫu đi kèm với Unity, hầu hết việc tiêm phụ thuộc được thực hiện bởi các thuộc tính với thuộc tính [Dependency].

Unity hoạt động rất tốt với XAML, nhưng chỉ khi bạn không sử dụng các nhà thầu được tham số hóa. Chuyển đổi UserControl của bạn để sử dụng các thuộc tính của nó bằng thuộc tính [Dependency] và bạn có thể dễ dàng sử dụng XAML.

public class MyUserControl : UserControl 
{ 
    [Dependency] 
    public ISomething Something { get; set; } 

    [Dependency] 
    public IWhatever Whatever { get { return (IWhatever)GetValue(WhateverProperty); } set { SetValue(WhateverProperty, value); } 
    public readonly DependencyProperty WhateverProperty = DependencyProperty.Register("Whatever", typeof(IWhatever), typeof(MyUserControl)); 

    ... 
} 

Lưu ý rằng thuộc tính [Phụ thuộc] có thể được khai báo dưới dạng Thuộc tính phụ thuộc hoặc thuộc tính CLR đơn giản như được hiển thị ở trên. Điều này nghe có vẻ như danh pháp khó hiểu nhưng trong thực tế nó rất đơn giản.

Để xác định UnityContainer trong XAML và nhận được cấu hình tự động, chỉ cần tạo một tài sản gắn liền thừa hưởng "UnityHelper.Container" mà PropertyChangedCallback chỉ đơn giản gọi tích tụ trên thùng sơn quy định và vượt qua trong loại của đối tượng và đối tượng:

public class UnityHelper 
{ 
    public static IUnityContainer GetContainer(DependencyObject obj) { return (IUnityContainer)obj.GetValue(ContainerProperty); } 
    public static void SetContainer(DependencyObject obj, IUnityContainer value) { obj.SetValue(ContainerProperty, value); } 
    public static readonly DependencyProperty ContainerProperty = DependencyProperty.RegisterAttached("Container", typeof(IUnityContainer), typeof(UnityHelper), new FrameworkPropertyMetadata 
    { 
    Inherits = true, 
    PropertyChangedCallback = (obj, e) => 
    { 
     var container = e.NewValue as IUnityContainer; 
     if(container!=null) 
     { 
     var element = obj as FrameworkElement; 
     container.BuildUp(obj.GetType(), obj, element==null ? null : element.Name); 
     } 
    } 
    }); 
} 

Bây giờ bạn có thể gán một UnityContainer để cửa sổ thư mục gốc của bạn và toàn bộ ứng dụng của bạn sẽ sử dụng nó, ví dụ bạn có thể làm điều đó trong constructor của cửa sổ của bạn như sau:

UnityHelper.SetContainer(this, new UnityContainer() ...); 

Hoặc bạn có thể gán container thống nhất sử dụng XAML tại bất kỳ mức độ mong muốn của cây:

<UserControl ... 
    my:UnityHelper.Container="{DynamicResource MainUnityContainer}" /> 

Có nói tất cả điều đó, tôi nghĩ rằng bạn sẽ sẽ thấy rằng dữ liệu tiên tiến WPF của tính năng và từ điển tài nguyên ràng buộc cùng nhau loại bỏ 98% trong những lý do tại sao một người đó có thể muốn sử dụng Unity ngay từ đầu. Bạn có thể tìm thấy nó tốt hơn trong thời gian dài để di chuyển ra khỏi Unity và đi với MVVM đơn giản. Ít nhất tôi sẽ thử MVVM thuần túy trên một ứng dụng thử nghiệm để xem nó hoạt động như thế nào trước khi phát triển nhiều mã dựa vào Unity để tiêm phụ thuộc.

+0

nó hoạt động, nhưng khi tôi nhấn nút tab từ một trong các hộp văn bản nó ném ngoại lệ Độ phân giải của phụ thuộc không thành công, type = "System.Windows.Input.KeyboardNavigation + FocusVisualAdorner", name = "". Thông báo ngoại lệ là: Hoạt động xây dựng hiện tại (khoá xây dựng Khóa [System.Windows.Input.KeyboardNavigation + FocusVisualAdorner, null]) không thành công: Không thể tải loại 'System.Windows.Input.KeyboardNavigation' từ assembly 'PresentationFramework, Version = 3.0 .0.0, Văn hóa = trung lập, PublicKeyToken = 31bf3856ad364e35 '. (Chiến lược loại BuildPlanStrategy, chỉ số 5) – Miral

+0

Câu trả lời này đã giúp tôi rất nhiều. Tôi ước tôi có thể cung cấp nhiều hơn +1. Tôi đã thêm chủ đề này vào "Mục yêu thích của tôi", nhưng điều đó chỉ ghi nhận anh chàng hỏi câu hỏi gốc. Cảm ơn! – Tormod

+0

Nếu bạn tạo một giao diện (gọi là IUnityElement) mà bạn áp dụng cho tất cả các UserControls hoặc Điều khiển, bạn cần thống nhất để chạy ngược lại trong dòng 'if (container! = Null)', bạn có thể kiểm tra xem tham số obj có thuộc giao diện đó không ví dụ 'if (container! = null && obj is IUnityInject)'. Điều này loại bỏ lỗi mà Miral đã nhận xét ở trên (tôi nhận được một lỗi tương tự từ một đối tượng khác và vấn đề về hiệu suất của câu trả lời ZeePrime, vì BuildUp chỉ chạy trên FrameworkElements mà bạn cần nó. –

0

Có vẻ khá dễ dàng. Tại sao bạn không chỉ cần thêm "một hàm tạo không tham số công khai" vào UserControl của mình? Bạn có thể chọn không sử dụng nó trong mã của bạn trực tiếp nhưng đó là những gì mà Nhà thiết kế đang tìm kiếm. Nếu bạn muốn chắc chắn nó không bao giờ được gọi là mã, hãy đặt a check for presence of Designer và ném một ngoại lệ nếu Nhà thiết kế không được phát hiện.

0

Nó hoạt động, nhưng hiệu suất khá xấu khi bạn sử dụng lưới hoặc màn hình WPF phức tạp. Inherits = true ngụ ý rằng tất cả các phần tử GUI được tạo sẽ có PropertyChangedCallback của thuộc tính đính kèm được gọi ngay sau hàm tạo, ngay cả khi phần tử GUI cụ thể đó không cần Unity chút nào. Và khi bạn có lưới, mỗi lần một hàng mới xuất hiện tất cả các yếu tố GUI được tạo ra khi đang bay, với cuộc gọi lại đó được gọi. điều này đã giết hiệu suất của lưới của chúng tôi, vì vậy chúng tôi đã phải loại bỏ UnityInjection thực hiện theo cách này.

Nhưng tuy nhiên có những nơi chúng tôi cần UnityInjection trong codebehind, và chúng tôi đã không tìm thấy một giải pháp tốt cho vấn đề này, ngay cả khi chúng tôi đang sử dụng MVVM. Một số điều khiển người dùng phức tạp được thiết kế bằng cách sử dụng MVVM, trong đó ViewModel của điều khiển được tạo bởi codebehind của chính điều khiển, được tạo bởi XAML đang sử dụng điều khiển. Trong trường hợp cụ thể này, ViewModel của bộ điều khiển không biết bất cứ điều gì (chưa) về Unity, nhưng chúng ta cần sự thống nhất Injection trong nó, để truy cập các tài nguyên bên ngoài có đăng ký.

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