2016-11-01 3 views
0

Pour lier les événements « chargés » et « débarquées » J'utilise le code suivant dans ma page XAML:Comment réutiliser Interaction Comportement dans XAML pour l'application WinRT avec une architecture MVVM

<Page ...> 
<interactivity:Interaction.Behaviors> 
    <core:EventTriggerBehavior EventName="Loaded"> 
     <core:InvokeCommandAction Command="{Binding LoadedCommand}" /> 
    </core:EventTriggerBehavior> 
    <core:EventTriggerBehavior EventName="Unloaded"> 
     <core:InvokeCommandAction Command="{Binding UnloadedCommand}" /> 
    </core:EventTriggerBehavior> 
</interactivity:Interaction.Behaviors> 
<Grid /> 
</Page> 

Tout fonctionne comme prévu cependant je copie ce même morceau de code dans chaque vue? Comment puis-je rendre cela réutilisable?

EDIT

J'ai créé une propriété attachée à l'aide du code dans cette post.

Ma propriété Attached ressemble à ceci:

public static class UiBehaviors 
{ 
    public static readonly DependencyProperty AttachedTriggersProperty = DependencyProperty.RegisterAttached("AttachedTriggers", typeof(EventTriggerCollection), typeof(UiBehaviors), new PropertyMetadata(null, OnAttachedTriggersChanged)); 

    private static void OnAttachedTriggersChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     BehaviorCollection triggers = Interaction.GetBehaviors(d); 

     if (e.OldValue != null) 
     { 
      foreach (EventTriggerBehavior trigger in (EventTriggerCollection)e.OldValue) 
       triggers.Remove(trigger); 
     } 

     if (e.NewValue == null) 
      return; 

     foreach (EventTriggerBehavior trigger in (EventTriggerCollection)e.NewValue) 
      triggers.Add(trigger); 

    } 

    public static void SetAttachedTriggers(DependencyObject element, EventTriggerCollection value) 
    { 
     element.SetValue(AttachedTriggersProperty, value); 
    } 

    public static EventTriggerCollection GetAttachedTriggers(DependencyObject element) 
    { 
     return (EventTriggerCollection)element.GetValue(AttachedTriggersProperty); 
    } 
} 

public class EventTriggerCollection : Collection<EventTriggerBehavior> 
{ 
} 

Mon Xaml ressemble à ceci:

<Style x:Name="Test" TargetType="UserControl"> 
    <Setter Property="storeApplication:UiBehaviors.AttachedTriggers"> 
     <Setter.Value> 
      <storeApplication:EventTriggerCollection> 
       <core:EventTriggerBehavior EventName="Loaded"> 
        <core:InvokeCommandAction Command="{Binding LoadedCommand}" /> 
       </core:EventTriggerBehavior> 
       <core:EventTriggerBehavior EventName="Unloaded"> 
        <core:InvokeCommandAction Command="{Binding UnloadedCommand}" /> 
       </core:EventTriggerBehavior> 
      </storeApplication:EventTriggerCollection> 
     </Setter.Value> 
    </Setter> 
</Style> 

Le x: shared = attribut Faux est requis sur le EventTriggerCollection pour créer un nouvel ensemble de déclencheurs chaque fois que la propriété est accessible. Sans cela, un déclencheur ne fonctionnera que pour le premier contrôle qui accède à la propriété.

Malheureusement, je ne peux pas utiliser cet attribut car il n'est pas pris en charge dans WinRT. Voir ceci post. Je suis maintenant bloqué :(Qu'est-ce que je manque

Répondre

2

Vous pouvez sous-classe votre page ou définir une propriété jointe qui fait la même chose dans un seul attribut

Par exemple, pour la solution de classe de base:.

MainPage.xaml

<local:MyAppPageBase 
    x:Class="App16.MainPage" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="using:App16" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    mc:Ignorable="d" 
    LoadedCommand="{Binding LoadedCommand}" 
    UnloadedCommand="{Binding UnloadedCommand}"> 
    <Grid /> 
</local:MyAppPageBase> 

MainPage.xaml.cs

using System.Windows.Input; 
using Windows.UI.Xaml; 
using Windows.UI.Xaml.Controls; 

namespace App16 
{ 
    public abstract class MyAppPageBase : Page 
    { 
     #region LoadedCommand 
     /// <summary> 
     /// LoadedCommand Dependency Property 
     /// </summary> 
     private static readonly DependencyProperty _LoadedCommandProperty = 
      DependencyProperty.Register(
       "LoadedCommand", 
       typeof(ICommand), 
       typeof(MyAppPageBase), 
       new PropertyMetadata(null)); 

     /// <summary> 
     /// Identifies the LoadedCommand dependency property. 
     /// </summary> 
     public static DependencyProperty LoadedCommandProperty { get { return _LoadedCommandProperty; } } 

     /// <summary> 
     /// Gets or sets the LoadedCommand property. This dependency property 
     /// indicates the command to execute when the page loads. 
     /// </summary> 
     public ICommand LoadedCommand 
     { 
      get { return (ICommand)GetValue(LoadedCommandProperty); } 
      set { this.SetValue(LoadedCommandProperty, value); } 
     } 
     #endregion 

     #region UnloadedCommand 
     /// <summary> 
     /// UnloadedCommand Dependency Property 
     /// </summary> 
     private static readonly DependencyProperty _UnloadedCommandProperty = 
      DependencyProperty.Register(
       "UnloadedCommand", 
       typeof(ICommand), 
       typeof(MyAppPageBase), 
       new PropertyMetadata(null)); 

     /// <summary> 
     /// Identifies the UnloadedCommand dependency property. 
     /// </summary> 
     public static DependencyProperty UnloadedCommandProperty { get { return _UnloadedCommandProperty; } } 

     /// <summary> 
     /// Gets or sets the UnloadedCommand property. This dependency property 
     /// indicates the command to execute when the page unloads. 
     /// </summary> 
     public ICommand UnloadedCommand 
     { 
      get { return (ICommand)GetValue(UnloadedCommandProperty); } 
      set { this.SetValue(UnloadedCommandProperty, value); } 
     } 
     #endregion 

     public MyAppPageBase() 
     { 
      this.Loaded += (s, e) => 
      { 
       if (LoadedCommand?.CanExecute(null) == true) 
       { 
        LoadedCommand.Execute(null); 
       } 
      }; 

      this.Unloaded += (s, e) => 
      { 
       if (UnloadedCommand?.CanExecute(null) == true) 
       { 
        UnloadedCommand.Execute(null); 
       } 
      }; 
     } 
    } 

    public sealed partial class MainPage : MyAppPageBase 
    { 
     public MainPage() 
     { 
      this.InitializeComponent(); 
     } 
    } 
} 

La propriété jointe (comportement joint) est un peu plus complexe car une propriété jointe doit s'assurer qu'elle ne provoque pas de fuites causées par des abonnements à des événements dans une classe statique, mais qu'elle ne nécessite pas de modification de base classes, ce qui est particulièrement utile si vous souhaitez réutiliser dans plus d'un projet, peut-être en le mettant dans un paquet NuGet:

MainPage.xaml

<Page 
    x:Class="App16.MainPage" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="using:App16" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    mc:Ignorable="d" 
    local:ElementExtensions.LoadedCommand="{Binding LoadedCommand}"> 
    <Grid /> 
</Page> 

MainPage.xaml.cs

using System; 
using System.Diagnostics; 
using System.Windows.Input; 
using Windows.UI.Xaml; 
using Windows.UI.Xaml.Controls; 

namespace App16 
{ 
    public static class ElementExtensions 
    { 
     #region LoadedCommand 
     /// <summary> 
     /// LoadedCommand Attached Dependency Property 
     /// </summary> 
     private static readonly DependencyProperty _LoadedCommandProperty = 
      DependencyProperty.RegisterAttached(
       "LoadedCommand", 
       typeof(ICommand), 
       typeof(ElementExtensions), 
       new PropertyMetadata(null, OnLoadedCommandChanged)); 

     /// <summary> 
     /// Identifies the LoadedCommand dependency property. 
     /// </summary> 
     public static DependencyProperty LoadedCommandProperty { get { return _LoadedCommandProperty; } } 

     /// <summary> 
     /// Gets the LoadedCommand property. This dependency property 
     /// indicates the command to execute when the element loads. 
     /// </summary> 
     public static ICommand GetLoadedCommand(DependencyObject d) 
     { 
      return (ICommand)d.GetValue(LoadedCommandProperty); 
     } 

     /// <summary> 
     /// Sets the LoadedCommand property. This dependency property 
     /// indicates the command to execute when the element loads. 
     /// </summary> 
     public static void SetLoadedCommand(DependencyObject d, ICommand value) 
     { 
      d.SetValue(LoadedCommandProperty, value); 
     } 

     /// <summary> 
     /// Handles changes to the LoadedCommand property. 
     /// </summary> 
     /// <param name="d"> 
     /// The <see cref="DependencyObject"/> on which 
     /// the property has changed value. 
     /// </param> 
     /// <param name="e"> 
     /// Event data that is issued by any event that 
     /// tracks changes to the effective value of this property. 
     /// </param> 
     private static void OnLoadedCommandChanged(
      DependencyObject d, DependencyPropertyChangedEventArgs e) 
     { 
      ICommand oldLoadedCommand = (ICommand)e.OldValue; 
      ICommand newLoadedCommand = (ICommand)d.GetValue(LoadedCommandProperty); 

      if (oldLoadedCommand != null) 
      { 
       var handler = GetLoadedCommandHandler(d); 
       handler?.Detach((FrameworkElement) d); 
      } 

      if (newLoadedCommand != null) 
      { 
       SetLoadedCommandHandler(d, new LoadedCommandHandler((FrameworkElement)d)); 
      } 
     } 
     #endregion 

     #region LoadedCommandHandler 
     /// <summary> 
     /// LoadedCommandHandler Attached Dependency Property 
     /// </summary> 
     private static readonly DependencyProperty _LoadedCommandHandlerProperty = 
      DependencyProperty.RegisterAttached(
       "LoadedCommandHandler", 
       typeof(LoadedCommandHandler), 
       typeof(ElementExtensions), 
       new PropertyMetadata(null)); 

     /// <summary> 
     /// Identifies the LoadedCommandHandler dependency property. 
     /// </summary> 
     public static DependencyProperty LoadedCommandHandlerProperty { get { return _LoadedCommandHandlerProperty; } } 

     /// <summary> 
     /// Gets the LoadedCommandHandler property. This dependency property 
     /// indicates the object that handles Loaded events on its owning element. 
     /// </summary> 
     internal static LoadedCommandHandler GetLoadedCommandHandler(DependencyObject d) 
     { 
      return (LoadedCommandHandler)d.GetValue(LoadedCommandHandlerProperty); 
     } 

     /// <summary> 
     /// Sets the LoadedCommandHandler property. This dependency property 
     /// indicates the object that handles Loaded events on its owning element. 
     /// </summary> 
     internal static void SetLoadedCommandHandler(DependencyObject d, LoadedCommandHandler value) 
     { 
      d.SetValue(LoadedCommandHandlerProperty, value); 
     } 
     #endregion 

     internal class LoadedCommandHandler 
     { 
      public LoadedCommandHandler(FrameworkElement element) 
      { 
       element.Loaded += OnLoaded; 
      } 

      public void Detach(FrameworkElement element) 
      { 
       element.Loaded -= OnLoaded; 
      } 

      private void OnLoaded(object sender, RoutedEventArgs e) 
      { 
       var command = GetLoadedCommand((DependencyObject) sender); 
       if (command?.CanExecute(null) == true) 
       { 
        command.Execute(null); 
       } 
      } 
     } 
    } 

    public sealed partial class MainPage : Page 
    { 
     public MainPage() 
     { 
      this.InitializeComponent(); 
      this.DataContext = new MyViewModel(); 
     } 
    } 

    public class MyViewModel 
    { 
     public ICommand LoadedCommand { get; private set; } = new MyCommand(); 
    } 

    public class MyCommand : ICommand 
    { 
     public bool CanExecute(object parameter) 
     { 
      return true; 
     } 

     public void Execute(object parameter) 
     { 
      Debug.WriteLine("Blahr"); 
     } 

     public event EventHandler CanExecuteChanged; 
    } 
} 
+0

Merci pour la réponse. J'ai essayé de définir une propriété attachée sans beaucoup de chance. Voir mon post édité. Avez-vous un exemple de "Sub Classing" une page Xaml? –

+0

@CoolBreeze Mis à jour ma réponse. –

+0

Merci pour les deux exemples. Je ai préféré la solution de comportement ci-joint :) –