Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
namespace Controls
{
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Markup;
/// <summary>
/// Displays a loading indicator.
/// </summary>
/// <remarks>
/// Use the IsLoading attached property to temporarily replace the content
/// of a ContentControl when set to true.
/// </remarks>
public sealed class AsyncIndicator : Control
{
/// <summary>
/// Identifies the IsLoading attached property.
/// </summary>
public static readonly DependencyProperty IsLoadingProperty =
DependencyProperty.RegisterAttached("IsLoading", typeof(bool), typeof(AsyncIndicator), new PropertyMetadata(false, OnIsLoadingChanged));
private static readonly DependencyProperty OriginalTemplateProperty =
DependencyProperty.RegisterAttached("OriginalTemplate", typeof(TemplateData), typeof(AsyncIndicator), new PropertyMetadata(null));
/// <summary>
/// Gets the value of the IsLoading attached property from the specified
/// object.
/// </summary>
/// <param name="obj">
/// The object from which to read the property value.
/// </param>
/// <returns>
/// The value of the IsLoading attached property on the target object.
/// </returns>
public static bool GetIsLoading(DependencyObject obj)
{
return (bool)obj.GetValue(IsLoadingProperty);
}
/// <summary>
/// Sets the value of the IsLoading attached property on the specified
/// object.
/// </summary>
/// <param name="obj">
/// The target object on which to set the property value.
/// </param>
/// <param name="value">The property value to set.</param>
public static void SetIsLoading(DependencyObject obj, bool value)
{
obj.SetValue(IsLoadingProperty, value);
}
protected override Size MeasureOverride(Size availableSize)
{
Size desiredSize = base.MeasureOverride(availableSize);
return new Size(
GetSize(availableSize.Width, desiredSize.Width),
GetSize(availableSize.Height, desiredSize.Height));
}
private static TemplateData BackupTemplateProperty(DependencyObject d)
{
TemplateData data = null;
DependencyProperty templateProperty = GetTemplateProperty(d);
if (templateProperty != null)
{
data = new TemplateData();
data.Property = templateProperty;
data.Template = d.GetValue(templateProperty);
}
d.SetValue(OriginalTemplateProperty, data);
return data;
}
private static double GetSize(double available, double desired)
{
return double.IsPositiveInfinity(available) ? desired : available;
}
private static DependencyProperty GetTemplateProperty(object element)
{
if (element is ContentControl)
{
return ContentControl.ContentTemplateProperty;
}
else if (element is HubSection)
{
return HubSection.ContentTemplateProperty;
}
return null;
}
private static void OnIsLoadingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if ((bool)e.NewValue)
{
TemplateData data = BackupTemplateProperty(d);
if (data != null)
{
SetIndicator(d, data);
}
}
else
{
RestoreTemplateProperty(d);
}
}
private static void RestoreTemplateProperty(DependencyObject d)
{
var data = (TemplateData)d.GetValue(OriginalTemplateProperty);
if (data != null)
{
d.SetValue(data.Property, data.Template);
d.ClearValue(OriginalTemplateProperty);
}
}
private static void SetIndicator(DependencyObject d, TemplateData data)
{
// Note: The namespace must match the namespace this class belongs to.
const string IndicatorDataTemplate =
@"<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
xmlns:local='using:Controls'>
<local:AsyncIndicator />
</DataTemplate>";
d.SetValue(data.Property, XamlReader.Load(IndicatorDataTemplate));
}
private class TemplateData
{
public DependencyProperty Property { get; set; }
public object Template { get; set; }
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment