Wpf usercontrol с параметризованным конструктором - PullRequest
5 голосов
/ 30 апреля 2010

Мы используем Microsoft Unity и внедрение зависимостей, поэтому у нас есть параметризованный конструктор для usercontrol. Как внедрить эту зависимость в usercontrol с использованием XAML?

Я добавил usercontrol в XAML, как показано ниже.

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

Ответы [ 3 ]

10 голосов
/ 18 мая 2010

Внедрение зависимостей не подразумевает параметризованные конструкторы. Фактически, если вы посмотрите на примеры, которые поставляются с Unity, большая часть внедрения зависимостей выполняется свойствами с атрибутом [Dependency].

Unity очень хорошо работает с XAML, но только если вы не используете параметризованные конструкторы. Преобразуйте свой UserControl, чтобы получить его зависимости, используя свойства с атрибутом [Dependency], и вы можете легко использовать 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));

  ...
}

Обратите внимание, что свойство [Dependency] может быть объявлено либо как DependencyProperty, либо как простое свойство CLR, как показано выше. Это звучит как запутанная номенклатура, но на практике это очень просто.

Чтобы указать UnityContainer в XAML и получить автоматическую настройку, просто создайте унаследованное вложенное свойство «UnityHelper.Container», у которого PropertyChangedCallback просто вызывает BuildUp для указанного контейнера и передает тип объекта и объект:

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

Теперь вы можете назначить UnityContainer для вашего корневого окна, и все ваше приложение будет использовать его, например, вы можете сделать это в конструкторе вашего окна следующим образом:

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

Или вы можете назначить контейнер единиц с помощью XAML на любом желаемом уровне дерева:

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

Сказав все это, я думаю, вы обнаружите, что расширенные функции связывания данных WPF и словари ресурсов вместе устраняют 98% причин, по которым человек может захотеть использовать Unity. Возможно, в конечном итоге вам будет лучше отойти от Unity и перейти на простой MVVM. По крайней мере, я бы попробовал чистый MVVM в тестовом приложении, чтобы увидеть, как оно работает, прежде чем разрабатывать много кода, использующего Unity для внедрения зависимостей.

0 голосов
/ 28 июля 2011

Это работает, но производительность довольно плохая, когда вы используете сетки или сложные экраны WPF. Inherits = true подразумевает, что все созданные элементы GUI будут иметь PropertyChangedCallback присоединенного свойства, вызываемого сразу после конструктора, даже если этот конкретный элемент GUI вообще не нуждается в Unity. А когда у вас есть сетки, каждый раз, когда появляется новая строка, все элементы графического интерфейса создаются на лету с вызовом этого обратного вызова. это убивало производительность нашей сетки, поэтому нам пришлось удалить UnityInjection, сделанную таким образом.

Но, тем не менее, есть места, где нам нужен UnityInjection в codebehind, и мы не нашли хорошего решения этой проблемы, даже если мы используем MVVM. Некоторый сложный пользовательский элемент управления разработан с использованием MVVM, где ViewModel элемента управления создается с помощью кода позади самого элемента управления, который создается XAML, использующим элемент управления. В этом конкретном случае ViewModel элемента управления ничего не знает (пока) о Unity, но нам НЕОБХОДИМО ввести в него инъекцию для единства, чтобы получить доступ к внешним ресурсам, зарегистрированным там.

0 голосов
/ 30 апреля 2010

Кажется довольно легко. Почему бы вам просто не добавить «открытый конструктор без параметров» к вашему UserControl? Вы можете не использовать его в своем коде напрямую, но это то, что ищет дизайнер. Если вы хотите убедиться, что он никогда не вызывается в коде, установите проверку на наличие Designer и сгенерируйте исключение, если Designer не обнаружен.

...