2015-09-22 17 views
5

La mia applicazione dispone di circa 15 diversi UserControl caricati uniformemente nell'area di contenuto in fase di runtime.Aggiungi trigger a ogni UserControl

Il mio progetto è al 100% MVVM-compliant, così ho il seguente XAML inserita in XAML di ogni UserControl:

<UserControl 
    ... 
    xmlns:intr="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 
> 

    <intr:Interaction.Triggers> 
     <intr:EventTrigger EventName="Loaded"> 
      <intr:InvokeCommandAction Command="{Binding ViewLoadedCommand}"/> 
     </intr:EventTrigger> 
    </intr:Interaction.Triggers> 

    <!-- Rest of UserControl content here --> 

</UserControl> 

Ovviamente questo non è l'ideale ed è anche una violazione della SECCO.

Qual è il modo migliore per applicare questo XAML a questo set di UserControls? (ma non ogni UserControl, quindi un semplice <Style Type="UserControl" /> sarebbe inappropriato).

+0

Perché non stile con una chiave? –

+0

@Nikita In realtà, non so come creare uno stile che imposta proprietà composite e complesse come "Interaction.Triggers". – Dai

+0

Dove si trova ViewLoadedCommand? Questo è nel tuo modello di vista? Sei sicuro di voler chiamare questo comando ** ogni volta ** viene caricato un controllo utente? –

risposta

0

è possibile creare un Usercontrol "base-load" con Interaction.Triggers e inserire semplicemente un ContentPresenter in cui si associa il contenuto reale.

<UserControl x:class="OneOfMyOtherControls"> 
    <MyBaseUserControl> 
    <!-- your UserControl Content--> 
    </MyBaseUserControl> 
</UserControl> 
4

Uso comportamento implementato come proprietà associata. Ha due importanti vantaggi rispetto a System.Windows.Interactivity:

  • può essere definito con stile.
  • molto meno codice XAML in vista

nel tuo caso, la vista potrebbe apparire come:

<UserControl ... 
      my:AttachedCommands.LoadedCommand="{Binding ViewLoadedCommand}"> 

Nella mia soluzione, non sto usando i comandi, ma chiamare metodi su ViewModel se il ViewModel implementa IViewModelLifeCycle interfaccia:

public interface IViewModelLifeCycle 
{ 
    void Activate(object extraData); 
    void Deactivate(); 
} 

Tutti i miei punti di vista utilizza questo stile:

0.123.
<Style x:Key="ViewBaseStyle"> 
    <Setter Property="my:ViewModelLifeCycleBehavior.ActivateOnLoad" Value="True" /> 

e il comportamento:

public static class ViewModelLifeCycleBehavior 
{ 
    public static readonly DependencyProperty ActivateOnLoadProperty = DependencyProperty.RegisterAttached("ActivateOnLoad", typeof (bool), typeof (ViewModelLifeCycleBehavior), 
     new PropertyMetadata(ActivateOnLoadPropertyChanged)); 

    public static void SetActivateOnLoad(FrameworkElement element, bool value) 
    { 
     element.SetValue(ActivateOnLoadProperty, value); 
    } 

    public static bool GetActivateOnLoad(FrameworkElement element) 
    { 
     return (bool)element.GetValue(ActivateOnLoadProperty); 
    } 


    private static void ActivateOnLoadPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) 
    { 
     if (DesignerProperties.GetIsInDesignMode(obj)) return; 
     var element = (FrameworkElement)obj; 

     element.Loaded -= ElementLoaded; 
     element.Unloaded -= ElementUnloaded; 

     if ((bool) args.NewValue == true) 
     { 
      element.Loaded += ElementLoaded; 
      element.Unloaded += ElementUnloaded; 
     } 
    } 



    static void ElementLoaded(object sender, RoutedEventArgs e) 
    { 
     var element = (FrameworkElement) sender; 
     var viewModel = (IViewModelLifeCycle) element.DataContext; 
     if (viewModel == null) 
     { 
      DependencyPropertyChangedEventHandler dataContextChanged = null; 
      dataContextChanged = (o, _e) => 
      { 
       ElementLoaded(sender, e); 
       element.DataContextChanged -= dataContextChanged; 
      }; 
      element.DataContextChanged += dataContextChanged; 
     } 
     else if (element.ActualHeight > 0 && element.ActualWidth > 0) //to avoid activating twice since loaded event is called twice on TabItems' subtrees 
     { 
      viewModel.Activate(null); 
     } 
    } 

    private static void ElementUnloaded(object sender, RoutedEventArgs e) 
    { 
     var element = (FrameworkElement)sender; 
     var viewModel = (IViewModelLifeCycle)element.DataContext; 
     viewModel.Deactivate(); 
    } 


} 

SUGGERIMENTO: Creare la custom Item Template in Visual Studio per View e ViewModel. è molto facile e consente di risparmiare un sacco di tempo. Il modello dell'articolo può contenere codice xaml con trigger/comportamento, che punta allo stile di base, alla definizione d:DataContext e alla classe viewmodel.

Problemi correlati