2016-11-01 47 views
0

要綁定「裝」和「卸載」我使用下面的代碼在我的XAML頁面事件:如何重用互動行爲中的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附加屬性。

我的附加屬性是這樣的:

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> 

的X:共享=需要在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

謝謝你們兩個例子。我更喜歡附加的行爲解決方案:) –

相關問題