Skip to content

Instantly share code, notes, and snippets.

@mfakane
Created October 28, 2011 15:40
Show Gist options
  • Save mfakane/1322573 to your computer and use it in GitHub Desktop.
Save mfakane/1322573 to your computer and use it in GitHub Desktop.
Bindable な ApplicationBar プロキシ
using System;
using System.Windows;
using System.Windows.Input;
using Microsoft.Phone.Reactive;
using Microsoft.Phone.Shell;
namespace Slashboard.Views
{
public class ApplicationBarIconButtonProxy : FrameworkElement
{
public static readonly DependencyProperty TextProperty = RegisterProperty<string>("Text", "Text");
public static readonly DependencyProperty IsEnabledProperty = RegisterProperty<bool>("IsEnabled");
public static readonly DependencyProperty IconUriProperty = RegisterProperty<Uri>("IconUri");
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("CommandProperty", typeof(ICommand), typeof(ApplicationBarIconButtonProxy), new PropertyMetadata((sender, e) =>
{
var d = (ApplicationBarIconButtonProxy)sender;
var command = (ICommand)e.NewValue;
if (d.commandHandler != null)
{
d.commandHandler.Dispose();
d.commandHandler = null;
}
if (command != null)
{
d.commandHandler = new CompositeDisposable
{
Observable.FromEvent<EventHandler, EventArgs>(_ => _.Invoke, _ => d.Internal.Click += _, _ => d.Internal.Click -= _)
.Where(_ => command.CanExecute(d.CommandParameter))
.Subscribe(_ => command.Execute(d.CommandParameter)),
Observable.FromEvent<EventHandler, EventArgs>(_ => _.Invoke, _ => command.CanExecuteChanged += _, _ => command.CanExecuteChanged -= _)
.Subscribe(_ => d.IsEnabled = command.CanExecute(d.CommandParameter)),
};
d.IsEnabled = command.CanExecute(d.CommandParameter);
}
}));
public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandProperty", typeof(object), typeof(ApplicationBarIconButtonProxy), new PropertyMetadata((sender, e) =>
{
var d = (ApplicationBarIconButtonProxy)sender;
if (d.Command != null)
d.IsEnabled = d.Command.CanExecute(d.CommandParameter);
}));
IDisposable commandHandler;
public event EventHandler Click
{
add
{
this.Internal.Click += value;
}
remove
{
this.Internal.Click -= value;
}
}
public object CommandParameter
{
get
{
return GetValue(CommandParameterProperty);
}
set
{
SetValue(CommandParameterProperty, value);
}
}
public ICommand Command
{
get
{
return (ICommand)GetValue(CommandProperty);
}
set
{
SetValue(CommandProperty, value);
}
}
public Uri IconUri
{
get
{
return (Uri)GetValue(IconUriProperty);
}
set
{
SetValue(IconUriProperty, value);
}
}
public bool IsEnabled
{
get
{
return (bool)GetValue(IsEnabledProperty);
}
set
{
SetValue(IsEnabledProperty, value);
}
}
public string Text
{
get
{
return (string)GetValue(TextProperty);
}
set
{
SetValue(TextProperty, value);
}
}
protected internal ApplicationBarIconButton Internal
{
get;
private set;
}
public ApplicationBarIconButtonProxy()
{
this.Internal = new ApplicationBarIconButton();
this.IconUri = this.Internal.IconUri;
this.IsEnabled = this.Internal.IsEnabled;
this.Text = this.Internal.Text;
}
static DependencyProperty RegisterProperty<T>(string name, T defaultValue = default(T))
{
return DependencyProperty.Register(name, typeof(T), typeof(ApplicationBarIconButtonProxy), new PropertyMetadata(defaultValue, (sender, e) =>
typeof(ApplicationBarIconButton).GetProperty(name).SetValue(((ApplicationBarIconButtonProxy)sender).Internal, (T)e.NewValue, null)));
}
}
}
using System;
using System.Windows;
using System.Windows.Input;
using Microsoft.Phone.Reactive;
using Microsoft.Phone.Shell;
namespace Slashboard.Views
{
public class ApplicationBarMenuItemProxy : FrameworkElement
{
public static readonly DependencyProperty TextProperty = RegisterProperty<string>("Text", "Text");
public static readonly DependencyProperty IsEnabledProperty = RegisterProperty<bool>("IsEnabled");
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("CommandProperty", typeof(ICommand), typeof(ApplicationBarMenuItemProxy), new PropertyMetadata((sender, e) =>
{
var d = (ApplicationBarMenuItemProxy)sender;
var command = (ICommand)e.NewValue;
if (d.commandHandler != null)
{
d.commandHandler.Dispose();
d.commandHandler = null;
}
if (command != null)
{
d.commandHandler = new CompositeDisposable
{
Observable.FromEvent<EventHandler, EventArgs>(_ => _.Invoke, _ => d.Internal.Click += _, _ => d.Internal.Click -= _)
.Where(_ => command.CanExecute(d.CommandParameter))
.Subscribe(_ => command.Execute(d.CommandParameter)),
Observable.FromEvent<EventHandler, EventArgs>(_ => _.Invoke, _ => command.CanExecuteChanged += _, _ => command.CanExecuteChanged -= _)
.Subscribe(_ => d.IsEnabled = command.CanExecute(d.CommandParameter)),
};
d.IsEnabled = command.CanExecute(d.CommandParameter);
}
}));
public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandProperty", typeof(object), typeof(ApplicationBarMenuItemProxy), new PropertyMetadata((sender, e) =>
{
var d = (ApplicationBarMenuItemProxy)sender;
if (d.Command != null)
d.IsEnabled = d.Command.CanExecute(d.CommandParameter);
}));
IDisposable commandHandler;
public event EventHandler Click
{
add
{
this.Internal.Click += value;
}
remove
{
this.Internal.Click -= value;
}
}
public object CommandParameter
{
get
{
return GetValue(CommandParameterProperty);
}
set
{
SetValue(CommandParameterProperty, value);
}
}
public ICommand Command
{
get
{
return (ICommand)GetValue(CommandProperty);
}
set
{
SetValue(CommandProperty, value);
}
}
public bool IsEnabled
{
get
{
return (bool)GetValue(IsEnabledProperty);
}
set
{
SetValue(IsEnabledProperty, value);
}
}
public string Text
{
get
{
return (string)GetValue(TextProperty);
}
set
{
SetValue(TextProperty, value);
}
}
protected internal ApplicationBarMenuItem Internal
{
get;
private set;
}
public ApplicationBarMenuItemProxy()
{
this.Internal = new ApplicationBarMenuItem();
this.IsEnabled = this.Internal.IsEnabled;
this.Text = this.Internal.Text;
}
static DependencyProperty RegisterProperty<T>(string name, T defaultValue = default(T))
{
return DependencyProperty.Register(name, typeof(T), typeof(ApplicationBarMenuItemProxy), new PropertyMetadata(defaultValue, (sender, e) =>
typeof(ApplicationBarMenuItem).GetProperty(name).SetValue(((ApplicationBarMenuItemProxy)sender).Internal, (T)e.NewValue, null)));
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
namespace Slashboard.Views
{
public class ApplicationBarProxy : ItemsControl, IApplicationBar
{
readonly ApplicationBar applicationBar = new ApplicationBar();
public static readonly new DependencyProperty OpacityProperty = RegisterProperty<double>("Opacity");
public static readonly DependencyProperty ForegroundColorProperty = RegisterProperty<Color>("ForegroundColor");
public static readonly DependencyProperty BackgroundColorProperty = RegisterProperty<Color>("BackgroundColor");
public static readonly DependencyProperty IsMenuEnabledProperty = RegisterProperty<bool>("IsMenuEnabled");
public static readonly DependencyProperty IsVisibleProperty = RegisterProperty<bool>("IsVisible");
public static readonly DependencyProperty ModeProperty = RegisterProperty<ApplicationBarMode>("Mode");
public ApplicationBarMode Mode
{
get
{
return (ApplicationBarMode)GetValue(ModeProperty);
}
set
{
SetValue(ModeProperty, value);
}
}
public bool IsVisible
{
get
{
return (bool)GetValue(IsVisibleProperty);
}
set
{
SetValue(IsVisibleProperty, value);
}
}
public bool IsMenuEnabled
{
get
{
return (bool)GetValue(IsMenuEnabledProperty);
}
set
{
SetValue(IsMenuEnabledProperty, value);
}
}
public Color BackgroundColor
{
get
{
return (Color)GetValue(BackgroundColorProperty);
}
set
{
SetValue(BackgroundColorProperty, value);
}
}
public Color ForegroundColor
{
get
{
return (Color)GetValue(ForegroundColorProperty);
}
set
{
SetValue(ForegroundColorProperty, value);
}
}
public new double Opacity
{
get
{
return (double)GetValue(OpacityProperty);
}
set
{
SetValue(OpacityProperty, value);
}
}
public event EventHandler<ApplicationBarStateChangedEventArgs> StateChanged
{
add
{
applicationBar.StateChanged += value;
}
remove
{
applicationBar.StateChanged -= value;
}
}
protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
e.NewItems.OfType<ApplicationBarIconButtonProxy>()
.Select(_ => _.Internal)
.ForEach(_ => applicationBar.Buttons.Add(_));
e.NewItems.OfType<ApplicationBarMenuItemProxy>()
.Select(_ => _.Internal)
.ForEach(_ => applicationBar.MenuItems.Add(_));
break;
case NotifyCollectionChangedAction.Remove:
e.OldItems.OfType<ApplicationBarIconButtonProxy>()
.Do(_ => _.ClearValue(ApplicationBarIconButtonProxy.DataContextProperty))
.Select(_ => _.Internal)
.ForEach(_ => applicationBar.Buttons.Remove(_));
e.OldItems.OfType<ApplicationBarMenuItemProxy>()
.Do(_ => _.ClearValue(ApplicationBarIconButtonProxy.DataContextProperty))
.Select(_ => _.Internal)
.ForEach(_ => applicationBar.MenuItems.Remove(_));
break;
case NotifyCollectionChangedAction.Replace:
var l = e.OldItems.Cast<object>()
.Zip(e.NewItems.Cast<object>(), (x, y) => new
{
From = x,
To = y,
});
l.Where(_ => _.From is ApplicationBarIconButtonProxy)
.ForEach(_ => applicationBar.Buttons[applicationBar.Buttons.IndexOf(((ApplicationBarIconButtonProxy)_.From).Internal)] = ((ApplicationBarIconButtonProxy)_.To).Internal);
l.Where(_ => _.From is ApplicationBarMenuItemProxy)
.ForEach(_ => applicationBar.MenuItems[applicationBar.MenuItems.IndexOf(((ApplicationBarMenuItemProxy)_.From).Internal)] = ((ApplicationBarMenuItemProxy)_.To).Internal);
break;
case NotifyCollectionChangedAction.Reset:
applicationBar.Buttons.Clear();
applicationBar.MenuItems.Clear();
break;
}
base.OnItemsChanged(e);
}
public ApplicationBarProxy()
{
this.Visibility = Visibility.Collapsed;
this.Opacity = applicationBar.Opacity;
this.ForegroundColor = applicationBar.ForegroundColor;
this.BackgroundColor = applicationBar.BackgroundColor;
this.IsMenuEnabled = applicationBar.IsMenuEnabled;
this.IsVisible = applicationBar.IsVisible;
this.Mode = applicationBar.Mode;
this.Loaded += (sender, e) => FindAncestor<PhoneApplicationPage>(this).First().ApplicationBar = applicationBar;
}
static IEnumerable<T> FindAncestor<T>(DependencyObject self)
where T : DependencyObject
{
var d = self;
while ((d = VisualTreeHelper.GetParent(d)) != null)
if (d is T)
yield return (T)d;
}
static DependencyProperty RegisterProperty<T>(string name)
{
return DependencyProperty.Register(name, typeof(T), typeof(ApplicationBarProxy), new PropertyMetadata((sender, e) =>
typeof(ApplicationBar).GetProperty(name).SetValue(((ApplicationBarProxy)sender).applicationBar, (T)e.NewValue, null)));
}
IList IApplicationBar.Buttons
{
get
{
return applicationBar.Buttons;
}
}
double IApplicationBar.DefaultSize
{
get
{
return applicationBar.DefaultSize;
}
}
IList IApplicationBar.MenuItems
{
get
{
return applicationBar.MenuItems;
}
}
double IApplicationBar.MiniSize
{
get
{
return applicationBar.MiniSize;
}
}
}
}
<phone:PhoneApplicationPage x:Class="Slashboard.Views.Page1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:v="clr-namespace:Slashboard.Views"
mc:Ignorable="d"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="728"
d:DesignWidth="480">
<Grid x:Name="LayoutRoot">
<v:ApplicationBarProxy>
<v:ApplicationBarIconButtonProxy IconUri="/icons/appbar.sync.rest.png"
Text="{Binding LocalizedResources.MainPageRefresh, Source={StaticResource LocalizedStrings}}"
Command="{Binding RefreshCommand}" />
<v:ApplicationBarIconButtonProxy IconUri="/icons/appbar.feature.search.rest.png"
Text="{Binding LocalizedResources.MainPageSearch, Source={StaticResource LocalizedStrings}}" />
<v:ApplicationBarMenuItemProxy Text="{Binding LocalizedResources.MainPageSettings, Source={StaticResource LocalizedStrings}}" />
</v:ApplicationBarProxy>
</Grid>
</phone:PhoneApplicationPage>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment