2010-12-15 101 views
1

App est en prism/mvvm/mef et utilise le chargement par attribut comme StockTraderRI.prisme: comment lier quelque chose dans shell.xaml à une variable de contenu de région?

Ma fenêtre shell contient un DockPanel pour un StatusBar, qui est global pour le shell, pas local pour chaque région.

ressemble à quelque chose comme ceci:

<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> 

Liaison à une variable globale ne fonctionne. Maintenant, je voudrais lier le StateMessage dans le StatusBarItem à la propriété StateMessage quel que soit le contrôle chargé dans MainRegion.
Ma première hypothèse était d'utiliser quelque chose comme:

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

Mais bien sûr, ne fonctionne pas, car Maincontent est pas StaticResource.

Quelqu'un peut-il me diriger vers un moyen de lier la propriété Text à une propriété de UserControl chargée dans MainRegion?

Répondre

2

Je ne pense pas que vous serez en mesure de trouver un moyen propre de lier directement à une propriété dans un objet dans une région. Une façon de procéder serait de faire en sorte que toutes les vues de la région spécifiée héritent d'une interface commune, de sorte qu'elles implémentent toutes la même propriété (disons, SystemName). Vous pouvez être capable de lier à un chemin qui inclut cette propriété et utiliser un ValueConverter pour modifier le type de System.Object au type d'interface. Le problème que j'ai avec cela est qu'il limite ce que vous pouvez mettre dans la région, et semble coupler le shell avec les types affichés dans le plus que je voudrais personnellement. Je suggère une route différente: puisque votre barre d'état fait partie de votre shell, avez un ViewModel pour le shell avec votre propriété à laquelle la barre d'état se lie, et qui utilise un événement pour suivre quand la valeur du statut change. Quelques avantages à le faire:

  1. Votre événement peut envoyer n'importe quel objet avec n'importe quel nombre de propriétés auxquelles votre shell peut se lier. Cela permet à d'autres choses que votre barre d'état de l'utiliser également.
  2. Les vues qui n'interagissent pas avec les différents objets de votre shell n'ont pas besoin de transmettre l'événement. Cela permet aux sous-vues d'un composant plus grand qui est affiché dans la région d'interagir avec le shell sans aucun effet, ou d'implémenter des interfaces dont elles n'ont pas besoin
  3. C'est un mécanisme bien défini dans le framework Prism, et donc un moyen attendu pour distribuer des informations

Notez que vous pouvez évidemment définir l'événement comme étant ce dont vous avez besoin - je viens de mettre un paramètre de type Object, mais vous voudriez probablement que ce soit plus spécifique à vos besoins globaux.

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

Maintenant, tous vos points de vue ont à faire est de mettre en œuvre IActiveAware, et augmenter l'événement quand ils deviennent actifs. Alternativement, vous pourriez avoir le ViewModel pour votre View faire cela (ce qui est probablement mieux, mais nécessiterait une communication supplémentaire.) here.

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