Created
April 3, 2014 08:59
-
-
Save ScottIsAFool/9950887 to your computer and use it in GitHub Desktop.
A behaviour to allow you to have a custom colour for the system tray's progressindicator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.ComponentModel; | |
using System.Windows; | |
using System.Windows.Controls; | |
using System.Windows.Interactivity; | |
using System.Windows.Media; | |
using Microsoft.Phone.Controls; | |
using Microsoft.Phone.Shell; | |
namespace ScottIsAFool.WindowsPhone.Behaviours | |
{ | |
/// <summary> | |
/// Behaviour that lets you set a custom colour for the system tray's progress indicator | |
/// </summary> | |
public class SystemTrayProgressIndicatorBehaviour : Behavior<PhoneApplicationPage> | |
{ | |
/// <summary> | |
/// The is visible property | |
/// </summary> | |
public static readonly DependencyProperty IsVisibleProperty = | |
DependencyProperty.Register("IsVisible", typeof (bool), typeof (SystemTrayProgressIndicatorBehaviour), new PropertyMetadata(true, OnIsVisibleChanged)); | |
/// <summary> | |
/// The dot color property | |
/// </summary> | |
public static readonly DependencyProperty DotColorProperty = | |
DependencyProperty.Register("DotColor", typeof (Color), typeof (SystemTrayProgressIndicatorBehaviour), new PropertyMetadata(GetDefaultColour(), OnDotColourChanged)); | |
/// <summary> | |
/// The dot matches foreground property | |
/// </summary> | |
public static readonly DependencyProperty DotMatchesForegroundProperty = | |
DependencyProperty.Register("DotMatchesForeground", typeof (bool), typeof (SystemTrayProgressIndicatorBehaviour), new PropertyMetadata(default(bool), OnDotMatchesForegroundChanged)); | |
/// <summary> | |
/// The value property | |
/// </summary> | |
public static readonly DependencyProperty ValueProperty = | |
DependencyProperty.Register("Value", typeof (double), typeof (SystemTrayProgressIndicatorBehaviour), new PropertyMetadata(default(double), OnValueChanged)); | |
/// <summary> | |
/// The is indeterminate property | |
/// </summary> | |
public static readonly DependencyProperty IsIndeterminateProperty = | |
DependencyProperty.Register("IsIndeterminate", typeof (bool), typeof (SystemTrayProgressIndicatorBehaviour), new PropertyMetadata(default(bool), OnIsIndeterminateChanged)); | |
/// <summary> | |
/// The text property | |
/// </summary> | |
public static readonly DependencyProperty TextProperty = | |
DependencyProperty.Register("Text", typeof (string), typeof (SystemTrayProgressIndicatorBehaviour), new PropertyMetadata(default(string), OnTextChanged)); | |
/// <summary> | |
/// The indicator | |
/// </summary> | |
private ProgressIndicator _indicator; | |
/// <summary> | |
/// The page | |
/// </summary> | |
private PhoneApplicationPage _page; | |
/// <summary> | |
/// The progress bar | |
/// </summary> | |
private ProgressBar _progressBar; | |
/// <summary> | |
/// The root panel | |
/// </summary> | |
private Panel _rootPanel; | |
/// <summary> | |
/// Gets or sets the text. | |
/// </summary> | |
/// <value> | |
/// The text. | |
/// </value> | |
public string Text | |
{ | |
get { return (string) GetValue(TextProperty); } | |
set { SetValue(TextProperty, value); } | |
} | |
/// <summary> | |
/// Gets or sets a value indicating whether this instance is indeterminate. | |
/// </summary> | |
/// <value> | |
/// <c>true</c> if this instance is indeterminate; otherwise, <c>false</c>. | |
/// </value> | |
public bool IsIndeterminate | |
{ | |
get { return (bool) GetValue(IsIndeterminateProperty); } | |
set { SetValue(IsIndeterminateProperty, value); } | |
} | |
/// <summary> | |
/// Gets or sets the value. | |
/// </summary> | |
/// <value> | |
/// The value. | |
/// </value> | |
public double Value | |
{ | |
get { return (double) GetValue(ValueProperty); } | |
set { SetValue(ValueProperty, value); } | |
} | |
/// <summary> | |
/// Gets or sets a value indicating whether this instance is visible. | |
/// </summary> | |
/// <value> | |
/// <c>true</c> if this instance is visible; otherwise, <c>false</c>. | |
/// </value> | |
public bool IsVisible | |
{ | |
get { return (bool) GetValue(IsVisibleProperty); } | |
set { SetValue(IsVisibleProperty, value); } | |
} | |
/// <summary> | |
/// Gets or sets the color of the dot. | |
/// </summary> | |
/// <value> | |
/// The color of the dot. | |
/// </value> | |
public Color DotColor | |
{ | |
get { return (Color) GetValue(DotColorProperty); } | |
set { SetValue(DotColorProperty, value); } | |
} | |
/// <summary> | |
/// Gets or sets a value indicating whether [dot matches foreground]. | |
/// </summary> | |
/// <value> | |
/// <c>true</c> if [dot matches foreground]; otherwise, <c>false</c>. | |
/// </value> | |
public bool DotMatchesForeground | |
{ | |
get { return (bool) GetValue(DotMatchesForegroundProperty); } | |
set { SetValue(DotMatchesForegroundProperty, value); } | |
} | |
/// <summary> | |
/// Gets the default colour. | |
/// </summary> | |
/// <returns></returns> | |
private static Color GetDefaultColour() | |
{ | |
if (DesignerProperties.IsInDesignTool) | |
{ | |
return default(Color); | |
} | |
return (Color) Application.Current.Resources["PhoneAccentColor"]; | |
} | |
/// <summary> | |
/// Called after the behavior is attached to an AssociatedObject. | |
/// </summary> | |
/// <remarks> | |
/// Override this to hook up functionality to the AssociatedObject. | |
/// </remarks> | |
protected override void OnAttached() | |
{ | |
AssociatedObject.LayoutUpdated += AssociatedObjectOnLayoutUpdated; | |
base.OnAttached(); | |
} | |
/// <summary> | |
/// Called when [is visible changed]. | |
/// </summary> | |
/// <param name="sender">The sender.</param> | |
/// <param name="e">The <see cref="DependencyPropertyChangedEventArgs" /> instance containing the event data.</param> | |
private static void OnIsVisibleChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) | |
{ | |
var b = sender as SystemTrayProgressIndicatorBehaviour; | |
if (b == null) | |
{ | |
return; | |
} | |
var isVisible = (bool) e.NewValue; | |
if (b._indicator == null || b._progressBar == null) | |
{ | |
return; | |
} | |
b._indicator.IsVisible = isVisible; | |
b._progressBar.Visibility = isVisible ? Visibility.Visible : Visibility.Collapsed; | |
} | |
/// <summary> | |
/// Called when [text changed]. | |
/// </summary> | |
/// <param name="sender">The sender.</param> | |
/// <param name="e">The <see cref="DependencyPropertyChangedEventArgs" /> instance containing the event data.</param> | |
private static void OnTextChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) | |
{ | |
var b = sender as SystemTrayProgressIndicatorBehaviour; | |
if (b == null) | |
{ | |
return; | |
} | |
var text = (string) e.NewValue; | |
if (b._indicator == null || b._progressBar == null) | |
{ | |
return; | |
} | |
b._indicator.Text = text; | |
} | |
/// <summary> | |
/// Called when [is indeterminate changed]. | |
/// </summary> | |
/// <param name="sender">The sender.</param> | |
/// <param name="e">The <see cref="DependencyPropertyChangedEventArgs" /> instance containing the event data.</param> | |
private static void OnIsIndeterminateChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) | |
{ | |
var b = sender as SystemTrayProgressIndicatorBehaviour; | |
if (b == null) | |
{ | |
return; | |
} | |
var isIndeterminate = (bool) e.NewValue; | |
if (b._indicator == null || b._progressBar == null) | |
{ | |
return; | |
} | |
b._progressBar.IsIndeterminate = isIndeterminate; | |
} | |
/// <summary> | |
/// Called when [dot colour changed]. | |
/// </summary> | |
/// <param name="sender">The sender.</param> | |
/// <param name="e">The <see cref="DependencyPropertyChangedEventArgs" /> instance containing the event data.</param> | |
private static void OnDotColourChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) | |
{ | |
var b = sender as SystemTrayProgressIndicatorBehaviour; | |
if (b == null) | |
{ | |
return; | |
} | |
var dotColour = (Color) e.NewValue; | |
if (b._indicator == null || b._progressBar == null) | |
{ | |
return; | |
} | |
b._progressBar.Foreground = new SolidColorBrush(dotColour); | |
} | |
/// <summary> | |
/// Called when [dot matches foreground changed]. | |
/// </summary> | |
/// <param name="sender">The sender.</param> | |
/// <param name="e">The <see cref="DependencyPropertyChangedEventArgs" /> instance containing the event data.</param> | |
private static void OnDotMatchesForegroundChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) | |
{ | |
var b = sender as SystemTrayProgressIndicatorBehaviour; | |
if (b == null) | |
{ | |
return; | |
} | |
var dotMatchesForeground = (bool) e.NewValue; | |
if (b._indicator == null || b._progressBar == null) | |
{ | |
return; | |
} | |
b._progressBar.Foreground = dotMatchesForeground ? new SolidColorBrush(SystemTray.GetForegroundColor(b._page)) : new SolidColorBrush(b.DotColor); | |
} | |
/// <summary> | |
/// Called when [value changed]. | |
/// </summary> | |
/// <param name="sender">The sender.</param> | |
/// <param name="e">The <see cref="DependencyPropertyChangedEventArgs" /> instance containing the event data.</param> | |
private static void OnValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) | |
{ | |
var b = sender as SystemTrayProgressIndicatorBehaviour; | |
if (b == null) | |
{ | |
return; | |
} | |
var value = (double) e.NewValue; | |
if (b._indicator == null || b._progressBar == null) | |
{ | |
return; | |
} | |
b._progressBar.Value = value; | |
} | |
/// <summary> | |
/// Associateds the object on layout updated. | |
/// </summary> | |
/// <param name="sender">The sender.</param> | |
/// <param name="eventArgs">The <see cref="EventArgs" /> instance containing the event data.</param> | |
/// <exception cref="System.Exception"> | |
/// This CustomColourSystemTrayBehaviour can only be attached to the main page | |
/// or | |
/// This CustomColourSystemTrayBehaviour requires a root element in the page called 'LayoutRoot' | |
/// </exception> | |
private void AssociatedObjectOnLayoutUpdated(object sender, EventArgs eventArgs) | |
{ | |
AssociatedObject.LayoutUpdated -= AssociatedObjectOnLayoutUpdated; | |
if (DesignerProperties.IsInDesignTool || AssociatedObject == null) | |
{ | |
return; | |
} | |
_page = AssociatedObject; | |
_indicator = new ProgressIndicator(); | |
_progressBar = new ProgressBar {VerticalAlignment = VerticalAlignment.Top, Margin = new Thickness(-12, 0, -12, 0)}; | |
_rootPanel = FindChild<Panel>(_page, "LayoutRoot"); | |
if (_page == null) | |
{ | |
throw new Exception("This CustomColourSystemTrayBehaviour can only be attached to the main page"); | |
} | |
if (_rootPanel == null) | |
{ | |
throw new Exception("This CustomColourSystemTrayBehaviour requires a root element in the page called 'LayoutRoot'"); | |
} | |
SetSystemTray(); | |
} | |
/// <summary> | |
/// Sets the system tray. | |
/// </summary> | |
private void SetSystemTray() | |
{ | |
if (DesignerProperties.IsInDesignTool || AssociatedObject == null) | |
{ | |
return; | |
} | |
_indicator.IsVisible = IsVisible; | |
double currentOpacity = SystemTray.GetOpacity(_page); | |
var border = new Border | |
{ | |
Background = new SolidColorBrush(SystemTray.GetBackgroundColor(_page)), | |
VerticalAlignment = VerticalAlignment.Top, | |
HorizontalAlignment = HorizontalAlignment.Stretch, | |
Opacity = SystemTray.GetOpacity(_page), | |
Height = 32 | |
}; | |
var grid = new Grid | |
{ | |
VerticalAlignment = VerticalAlignment.Top, | |
HorizontalAlignment = HorizontalAlignment.Stretch, | |
Height = 32 | |
}; | |
if (currentOpacity == 1) | |
{ | |
SystemTray.SetOpacity(_page, 0); | |
grid.Margin = new Thickness(0, -32, 0, 0); | |
if (_rootPanel != null) | |
{ | |
_rootPanel.Margin = new Thickness(_rootPanel.Margin.Left, _rootPanel.Margin.Top + 32, _rootPanel.Margin.Right, _rootPanel.Margin.Bottom); | |
} | |
} | |
_indicator.Text = Text; | |
_progressBar.IsIndeterminate = IsIndeterminate; | |
_progressBar.Value = Value; | |
_progressBar.Visibility = IsVisible ? Visibility.Visible : Visibility.Collapsed; | |
_progressBar.Foreground = DotMatchesForeground ? new SolidColorBrush(SystemTray.GetForegroundColor(_page)) : new SolidColorBrush(DotColor); | |
grid.Children.Add(border); | |
grid.Children.Add(_progressBar); | |
if (_rootPanel != null) | |
{ | |
Grid.SetRowSpan(grid, 1000); | |
Grid.SetColumnSpan(grid, 1000); | |
_rootPanel.Children.Add(grid); | |
} | |
SystemTray.SetProgressIndicator(_page, _indicator); | |
} | |
/// <summary> | |
/// Finds the child. | |
/// </summary> | |
/// <typeparam name="T">The return type</typeparam> | |
/// <param name="parent">The parent.</param> | |
/// <param name="childName">Name of the child.</param> | |
/// <returns>The child element if found</returns> | |
public static T FindChild<T>(DependencyObject parent, string childName) | |
where T : DependencyObject | |
{ | |
// Confirm parent and childName are valid. | |
if (parent == null) | |
{ | |
return null; | |
} | |
T foundChild = null; | |
int childrenCount = VisualTreeHelper.GetChildrenCount(parent); | |
for (int i = 0; i < childrenCount; i++) | |
{ | |
DependencyObject child = VisualTreeHelper.GetChild(parent, i); | |
// If the child is not of the request child type child | |
var childType = child as T; | |
if (childType == null) | |
{ | |
// recursively drill down the tree | |
foundChild = FindChild<T>(child, childName); | |
// If the child is found, break so we do not overwrite the found child. | |
if (foundChild != null) | |
{ | |
break; | |
} | |
} | |
else if (!string.IsNullOrEmpty(childName)) | |
{ | |
var frameworkElement = child as FrameworkElement; | |
// If the child's name is set for search | |
if (frameworkElement != null && frameworkElement.Name == childName) | |
{ | |
// if the child's name is of the request name | |
foundChild = (T) child; | |
break; | |
} | |
// Need this in case the element we want is nested | |
// in another element of the same type | |
foundChild = FindChild<T>(child, childName); | |
} | |
else | |
{ | |
// child element found. | |
foundChild = (T) child; | |
break; | |
} | |
} | |
return foundChild; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment