昨日のブログの最後に 「そういえば XAML で操作できないんですかね?」と書いていたところ、かずきさんからアドバイスを頂きました。
@kazuakix びへいびゃー作るとか?
— かずき@虚脱 (@okazuki) 2014, 8月 21
そういえばビヘイビアって使ったことなかったんですよね...と「 Behavior 作り方」で検索してみると次のページがヒットしました。
「ステマかキサマッ!!」っと東に向かって叫びそうになりながら内容を確認します。
この記事 (WPF) では Behavior<> を継承したクラスを作るようですね。ただ、Windows Phone 8.1 (というか WinRT) には Behavior<> はありませんでした。
早速、「 WinRT Behavior 」を検索してみます。
孫悟空にでもなった気分ですが、リンク先のコードレシピを確認します。どうやら Behaviors SDK というものを使えばいいようですね。
後はリンク先に全て書いてありますが、せっかくなので自分でもやってみます。
まずは 参照設定から Behaviors SDK を追加しましょう。
次に新しいクラス (今回は AppBarBehavior とします) を追加して、DependencyObject と IBehavior を継承します。
IBehavior については必要なプロパティ、メソッドを実装しておきます。
AssociatedObject にビヘイビアをセットする要素(今回だと Page) をセットし、 Attach() で前処理、Detach() で後処理をすればいいみたいです。
上記ページを参考にしながら、こんな感じにしてみました。
public class AppBarBehavior : DependencyObject, IBehavior { public DependencyObject AssociatedObject { get; private set;} public void Attach(DependencyObject associatedObject) { this.AssociatedObject = associatedObject; ((FrameworkElement)this.AssociatedObject).Loaded += this.AssociatedObjectLoaded; } private void AssociatedObjectLoaded(object sender, RoutedEventArgs e) { throw new System.NotImplementedException(); } public void Detach() { ((FrameworkElement)this.AssociatedObject).Loaded -= this.AssociatedObjectLoaded; this.AssociatedObject = null; } }
これでアタッチした要素がロードされたときに AssociatedObjectLoaded() が呼び出されます。とりあえず昨日のコードを書いておきましょう。
private async void AssociatedObjectLoaded(object sender, RoutedEventArgs e) { var statusBar = Windows.UI.ViewManagement.StatusBar.GetForCurrentView(); statusBar.BackgroundColor = Windows.UI.Color.FromArgb(255, 168, 17, 31); statusBar.BackgroundOpacity = 1; statusBar.ProgressIndicator.Text = "App7"; statusBar.ProgressIndicator.ProgressValue = 0; await statusBar.ProgressIndicator.ShowAsync(); }
このコードをビルドして Blend を開いてみると ビヘイビアの中に AppBarBehavior ができているので、Page にドラッグ & ドロップしてやります。
デザイナ上では何も変化がありませんが、実行してみるとこの通り。
これでページごとに同じコード書かなくて済みますね。
最後にやっつけでタイトルと背景色をプロパティにしてみました。
using Microsoft.Xaml.Interactivity; using System; using Windows.UI.Xaml; using Windows.UI.Xaml.Media; namespace App7 { public class AppBarBehavior : DependencyObject, IBehavior { public string Title { get { return (string)GetValue(TitleProperty); } set { SetValue(TitleProperty, value); } } public static readonly DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(AppBarBehavior), new PropertyMetadata("", new PropertyChangedCallback(OnTitleChanged))); private static void OnTitleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var thisinstance = d as AppBarBehavior; thisinstance.ShowStatusBarTitle((string)e.NewValue); } public SolidColorBrush Background { get { return (SolidColorBrush)GetValue(BackgroundProperty); } set { SetValue(BackgroundProperty, value); } } public static readonly DependencyProperty BackgroundProperty = DependencyProperty.Register("Background", typeof(SolidColorBrush), typeof(AppBarBehavior), new PropertyMetadata(null, new PropertyChangedCallback(OnBackgroundChanged))); private static void OnBackgroundChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var thisinstance = d as AppBarBehavior; thisinstance.ShowStatusBar(e.NewValue as SolidColorBrush); } public DependencyObject AssociatedObject { get; private set;} public AppBarBehavior() { this.Title = string.Empty; this.Background = (App.Current.Resources["PhoneAccentBrush"]) as SolidColorBrush; } public void Attach(DependencyObject associatedObject) { this.AssociatedObject = associatedObject; ((FrameworkElement)this.AssociatedObject).Loaded += this.AssociatedObjectLoaded; } private void AssociatedObjectLoaded(object sender, RoutedEventArgs e) { ShowStatusBar(this.Background); ShowStatusBarTitle(this.Title); } private void ShowStatusBar(SolidColorBrush background) { var statusBar = Windows.UI.ViewManagement.StatusBar.GetForCurrentView(); statusBar.BackgroundColor = background.Color; statusBar.BackgroundOpacity = 1; } private async void ShowStatusBarTitle(string title) { var statusBar = Windows.UI.ViewManagement.StatusBar.GetForCurrentView(); statusBar.ProgressIndicator.Text = title; statusBar.ProgressIndicator.ProgressValue = 0; await statusBar.ProgressIndicator.ShowAsync(); } public void Detach() { ((FrameworkElement)this.AssociatedObject).Loaded -= this.AssociatedObjectLoaded; this.AssociatedObject = null; } } }
一応、こんな感じで指定できるようになります。
<Interactivity:Interaction.Behaviors> <local:AppBarBehavior Background="#FF006699" Title="MyApp"/> </Interactivity:Interaction.Behaviors>