призма: как связать что-то в shell.xaml с переменной содержимого региона? - PullRequest
1 голос
/ 15 декабря 2010

Приложение находится в prism / mvvm / mef и использует загрузку по атрибуту, например StockTraderRI.

Окно моей оболочки содержит DockPanel для StatusBar, который является глобальным для оболочки, а не локальным для каждого региона.

выглядит примерно так:

<DockPanel>
  <StatusBar DockPanel.Dock="Bottom">
    <StatusBarItem>
      <TextBlock Text="{Binding Source={x:Static bcl:Configuration.Global}, Path=LoggedOn.User}"/>
    </StatusBarItem>
    <StatusBarItem>
      <TextBlock Text="{Binding StateMessage}"/>
    </StatusBarItem>
  </StatusBar>
  <ContentControl x:Name="MainContent" cal:RegionManager.RegionName="MainRegion"/>
</DockPanel>

Привязка к глобальной переменной работает хорошо. Теперь я хотел бы связать StateMessage в StatusBarItem со свойством StateMessage в любом элементе управления, загруженном в MainRegion.
Моим первым предположением было использовать что-то вроде:

<TextBlock Text="{Binding Path=DataContext.StateMessage,Source={StaticResource MainContent}}"/>

Но это, конечно, не работает, поскольку MainContent не является StaticResource.

Может кто-нибудь указать мне способ привязки свойства Text к какому-либо свойству UserControl, загруженному в MainRegion?

1 Ответ

2 голосов
/ 24 декабря 2010

Я не думаю, что вы сможете найти чистый способ привязки непосредственно к свойству объекта в регионе.Один из способов сделать это может состоять в том, чтобы все представления в указанном регионе наследовали от общего интерфейса, чтобы они все реализовывали одно и то же свойство (скажем, SystemName).Вы можете связать путь с этим свойством и использовать ValueConverter, чтобы изменить тип с System.Object на тип интерфейса.

Проблема, с которой я столкнулся, заключается в том, что она ограничивает то, что вы можетеположить в регион, и, кажется, связать оболочку с типами, отображаемыми в нем больше, чем я лично хотел бы.Я бы предложил другой маршрут: поскольку ваша строка состояния является частью вашей оболочки, у вас должна быть ViewModel для оболочки с вашим свойством, к которому привязывается строка состояния, и которая использует событие для отслеживания изменения значения состояния.Это дает несколько преимуществ:

  1. Ваше событие может отправить любой объект с любым количеством свойств, с которыми может связываться ваша оболочка.Это позволяет другим вещам, кроме строки состояния, также использовать ее.
  2. Представления, которые не взаимодействуют с различными объектами в вашей оболочке, не должны передавать событие.Это позволяет подпредставлениям более крупного компонента, отображаемого в регионе, не взаимодействовать с оболочкой неблагоприятно или реализовывать любые интерфейсы, которые им не нужны
  3. . Это хорошо определенный механизм в структуре Prism, и, следовательно,ожидаемый способ распространения информации

Обратите внимание, что вы, очевидно, можете определить событие как то, что вам нужно - я просто ввел параметр типа Object, но вы, вероятно, захотите, чтобы это было более конкретнымк вашим общим потребностям.

// Use normal binding for Shell -> ShellViewModel
public sealed ShellViewModel : INotifyPropertyChanged
{
   private readonly IEventAggregator = eventAggregator;

   public ShellViewModel(IEventAggregator eventAggregator)
   {
      _eventAggregator = eventAggregator;

      _eventAggregator.GetEvent<MainRegionViewLoaded>.Subscribe(
         new Action<Object>(HandleMainRegionViewLoaded));
   }

   private String _statusName;
   public String StatusName
   {
      get { return _statusName; }
      set
      {
         if (_statusName != value)
         {
            _statusName = value;
            RaisePropertyChanged("StatusName"); // Not showing this...
         }
      }
   }

   private void HandleMainRegionViewLoaded(Object param)
   {
      // Not doing all the checking here, such as null, etc.
      var statusName = param as String;
      StatusName = statusName;
   }
}

Теперь все, что вам нужно сделать, это реализовать IActiveAware и вызвать событие, когда они станут активными.В качестве альтернативы, вы могли бы сделать так, чтобы ViewModel для вашего View делал это (что, вероятно, лучше, но потребовало бы некоторого дополнительного взаимодействия. Здесь есть некоторое объяснение здесь ).

public void MainView : UserControl, IActiveAware
{

   private readonly IEventAggregator _eventAggregator;

   public MainView(IEventAggregator eventAggregator)
   {
      InitializeComponent();

      _eventAggregator = eventAggregator;
   }

   private bool _isActive;
   public bool IsActive
   {
      get { return _isActive; }
      set
      {
         if (value)
         {
            _eventAggregator.GetEvent<MainRegionViewLoaded>.Publish(new MainRegionViewLoaded("My Name"));
         }
         _isActive = value;
      }
   }
}
...