2016-11-01 9 views
0

Чтобы связать «нагруженное» и «разгружали» событие я использую следующий код в моей странице XAML:Как повторно использовать Interaction Поведения в XAML для WinRT приложения с архитектурой 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> 

Все работает, как ожидалось однако я копирую этот же бит кода во все виды? Как я могу сделать это для повторного использования?

EDIT

Я создал вложенное свойство с помощью кода в этом post.

Моя Attached свойство выглядит следующим образом:

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

Мои Xaml выглядит следующим образом:

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

рент-: Shared = False атрибут требуется на EventTriggerCollection, чтобы создать новый набор триггеров каждый раз при доступе к объекту. Без него триггер будет работать только для первого элемента управления, который обращается к свойству.

К сожалению, я не могу использовать этот атрибут, потому что он не поддерживается в WinRT. См. Это post. Я сейчас застрял :(Что я упускаю

ответ

2

Вы можете создать подкласс страницу или определить вложенное свойство, которое делает то же самое в одном атрибуте

Например, для базового класса решения:?.

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

Решение, связанное с приложением (приложенное поведение), является более сложным, поскольку прикрепленное свойство должно быть уверенным, что оно не приведет к утечкам, вызванным подписками на события в статическом классе, но имеет преимущество не требовать изменения базы классы, что особенно полезно, если вы хотите использовать его в более чем одном проекте, возможно, поместив его в пакет 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

Благодарим за отзыв. Я попытался определить прикрепленное свойство без большой удачи. См. Мой отредактированный пост. У вас есть пример «Sub Classing» на странице Xaml? –

+0

@CoolBreeze Обновлен мой ответ. –

+0

Благодарим вас за оба примера. Я предпочел приложенное решение поведения :) –

 Смежные вопросы

  • Нет связанных вопросов^_^