Add project files.

This commit is contained in:
2017-02-05 20:14:11 +02:00
parent 7950426bba
commit 824363a7ee
113 changed files with 6105 additions and 0 deletions
@@ -0,0 +1,115 @@
using System;
using System.Collections;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
using System.Windows.Media;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
namespace Phone7.Fx.Preview
{
[ContentProperty("Buttons")]
public class BindableApplicationBar : ItemsControl, IApplicationBar
{
private readonly ApplicationBar _applicationBar;
public BindableApplicationBar()
{
_applicationBar = new ApplicationBar();
this.Loaded += new RoutedEventHandler(BindableApplicationBar_Loaded);
}
void BindableApplicationBar_Loaded(object sender, RoutedEventArgs e)
{
var page =
this.GetVisualAncestors().Where(c => c is PhoneApplicationPage).FirstOrDefault() as PhoneApplicationPage;
if (page != null) page.ApplicationBar = _applicationBar;
}
protected override void OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
base.OnItemsChanged(e);
_applicationBar.Buttons.Clear();
_applicationBar.MenuItems.Clear();
foreach (BindableApplicationBarIconButton button in Items.Where(c => c is BindableApplicationBarIconButton))
{
_applicationBar.Buttons.Add(button.Button);
}
foreach (BindableApplicationBarMenuItem button in Items.Where(c => c is BindableApplicationBarMenuItem))
{
_applicationBar.MenuItems.Add(button.MenuItem);
}
}
public static readonly DependencyProperty IsVisibleProperty =
DependencyProperty.RegisterAttached("IsVisible", typeof(bool), typeof(BindableApplicationBar), new PropertyMetadata(true, OnVisibleChanged));
private static void OnVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue != e.OldValue)
{
((BindableApplicationBar)d)._applicationBar.IsVisible = (bool)e.NewValue;
}
}
public static readonly DependencyProperty IsMenuEnabledProperty =
DependencyProperty.RegisterAttached("IsMenuEnabled", typeof(bool), typeof(BindableApplicationBar), new PropertyMetadata(true, OnEnabledChanged));
private static void OnEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue != e.OldValue)
{
((BindableApplicationBar)d)._applicationBar.IsMenuEnabled = (bool)e.NewValue;
}
}
public bool IsVisible
{
get { return (bool)GetValue(IsVisibleProperty); }
set { SetValue(IsVisibleProperty, value); }
}
public double BarOpacity
{
get { return _applicationBar.Opacity; }
set { _applicationBar.Opacity = value; }
}
public bool IsMenuEnabled
{
get { return (bool)GetValue(IsMenuEnabledProperty); }
set { SetValue(IsMenuEnabledProperty, value); }
}
public Color BackgroundColor
{
get { return _applicationBar.BackgroundColor; }
set { _applicationBar.BackgroundColor = value; }
}
public Color ForegroundColor
{
get { return _applicationBar.ForegroundColor; }
set { _applicationBar.ForegroundColor = value; }
}
public ApplicationBarMode Mode { get; set; }
public double DefaultSize { get; private set; }
public double MiniSize { get; private set; }
public IList Buttons
{
get { return this.Items; }
}
public IList MenuItems
{
get { return this.Items; }
}
public event EventHandler<ApplicationBarStateChangedEventArgs> StateChanged;
}
}
@@ -0,0 +1,98 @@
using System;
using System.Windows;
using System.Windows.Input;
using Microsoft.Phone.Shell;
namespace Phone7.Fx.Preview
{
public class BindableApplicationBarIconButton : FrameworkElement, IApplicationBarIconButton, IApplicationBarMenuItem
{
public static readonly DependencyProperty CommandProperty =
DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(BindableApplicationBarIconButton), null);
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
public static readonly DependencyProperty CommandParameterProperty =
DependencyProperty.RegisterAttached("CommandParameter", typeof(object), typeof(BindableApplicationBarIconButton), null);
public object CommandParameter
{
get { return GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}
public static readonly DependencyProperty CommandParameterValueProperty =
DependencyProperty.RegisterAttached("CommandParameterValue", typeof(object), typeof(BindableApplicationBarMenuItem), null);
public object CommandParameterValue
{
get { return GetValue(CommandParameterValueProperty); }
set { SetValue(CommandParameterValueProperty, value); }
}
public static readonly DependencyProperty IsEnabledProperty =
DependencyProperty.RegisterAttached("IsEnabled", typeof(bool), typeof(BindableApplicationBarIconButton), new PropertyMetadata(true, OnEnabledChanged));
private static void OnEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue != e.OldValue)
{
((BindableApplicationBarIconButton)d).Button.IsEnabled = (bool)e.NewValue;
}
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.RegisterAttached("Text", typeof(string), typeof(BindableApplicationBarIconButton), new PropertyMetadata(OnTextChanged));
private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue != e.OldValue)
{
((BindableApplicationBarIconButton)d).Button.Text = e.NewValue.ToString();
}
}
public ApplicationBarIconButton Button { get; set; }
public BindableApplicationBarIconButton()
{
Button = new ApplicationBarIconButton();
Button.Text = "Text";
Button.Click += ApplicationBarIconButtonClick;
}
void ApplicationBarIconButtonClick(object sender, EventArgs e)
{
if (Command != null && CommandParameter != null)
Command.Execute(CommandParameter);
else if (Command != null)
Command.Execute(CommandParameterValue);
}
public bool IsEnabled
{
get { return (bool)GetValue(IsEnabledProperty); }
set { SetValue(IsEnabledProperty, value); }
}
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public event EventHandler Click;
public Uri IconUri
{
get { return Button.IconUri; }
set { Button.IconUri = value; }
}
}
}
@@ -0,0 +1,94 @@
using System;
using System.Windows;
using System.Windows.Input;
using Microsoft.Phone.Shell;
namespace Phone7.Fx.Preview
{
public class BindableApplicationBarMenuItem : FrameworkElement, IApplicationBarMenuItem
{
public static readonly DependencyProperty CommandProperty =
DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(BindableApplicationBarMenuItem), null);
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
public static readonly DependencyProperty CommandParameterProperty =
DependencyProperty.RegisterAttached("CommandParameter", typeof(object), typeof(BindableApplicationBarMenuItem), null);
public object CommandParameter
{
get { return GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}
public static readonly DependencyProperty CommandParameterValueProperty =
DependencyProperty.RegisterAttached("CommandParameterValue", typeof(object), typeof(BindableApplicationBarMenuItem), null);
public object CommandParameterValue
{
get { return GetValue(CommandParameterValueProperty); }
set { SetValue(CommandParameterValueProperty, value); }
}
public static readonly DependencyProperty IsEnabledProperty =
DependencyProperty.RegisterAttached("IsEnabled", typeof(bool), typeof(BindableApplicationBarMenuItem), new PropertyMetadata(true, OnEnabledChanged));
private static void OnEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue != e.OldValue)
{
((BindableApplicationBarMenuItem)d).MenuItem.IsEnabled = (bool)e.NewValue;
}
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.RegisterAttached("Text", typeof(string), typeof(BindableApplicationBarMenuItem), new PropertyMetadata(OnTextChanged));
private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue != e.OldValue)
{
((BindableApplicationBarMenuItem)d).MenuItem.Text = e.NewValue.ToString();
}
}
public ApplicationBarMenuItem MenuItem { get; set; }
public BindableApplicationBarMenuItem()
{
MenuItem = new ApplicationBarMenuItem();
MenuItem.Text = "Text";
MenuItem.Click += ApplicationBarMenuItemClick;
}
void ApplicationBarMenuItemClick(object sender, EventArgs e)
{
if (Command != null && CommandParameter != null)
Command.Execute(CommandParameter);
else if (Command != null)
Command.Execute(CommandParameterValue);
}
public bool IsEnabled
{
get { return (bool)GetValue(IsEnabledProperty); }
set { SetValue(IsEnabledProperty, value); }
}
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public event EventHandler Click;
}
}
+190
View File
@@ -0,0 +1,190 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Runtime.Serialization;
namespace Phone7.Fx.Preview
{
/// <summary>
///
/// </summary>
public class Cache
{
public static readonly DateTime NoAbsoluteExpiration = DateTime.MaxValue;
public static readonly TimeSpan NoSlidingExpiration = TimeSpan.Zero;
readonly IsolatedStorageFile _myStore = IsolatedStorageFile.GetUserStoreForApplication();
private object _sync = new object();
private static Cache _current;
/// <summary>
/// Gets the current instance of the cache
/// </summary>
/// <value>The current.</value>
public static Cache Current
{
get { return _current ?? (_current = new Cache()); }
}
/// <summary>
/// Adds the specified key.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="value">The value.</param>
/// <param name="absoluteExpiration">The absolute expiration.</param>
/// <param name="slidingExpiration">The sliding expiration.</param>
public void Add(string key, object value, DateTime absoluteExpiration, TimeSpan slidingExpiration)
{
lock (_sync)
{
if (Contains(key))
Remove(key);
if (absoluteExpiration == NoAbsoluteExpiration)
Add(key, DateTime.UtcNow + slidingExpiration, value);
if (slidingExpiration == NoSlidingExpiration)
Add(key, absoluteExpiration, value);
}
}
/// <summary>
/// Adds the specified key.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="expirationDate">The expiration date.</param>
/// <param name="value">The value.</param>
private void Add(string key, DateTime expirationDate, object value)
{
lock (_sync)
{
if (!_myStore.DirectoryExists(key))
_myStore.CreateDirectory(key);
else
{
string currentFile = GetFileNames(key).FirstOrDefault();
if (currentFile != null)
_myStore.DeleteFile(string.Format("{0}\\{1}", key, currentFile));
_myStore.DeleteDirectory(key);
_myStore.CreateDirectory(key);
}
string fileName = string.Format("{0}\\{1}.cache", key, expirationDate.ToFileTimeUtc());
if (_myStore.FileExists(fileName))
_myStore.DeleteFile(fileName);
NormalWrite(fileName, value);
}
}
/// <summary>
/// Determines whether the cache contains the specified key.
/// </summary>
/// <param name="key">The key.</param>
/// <returns>
/// <c>true</c> if [contains] [the specified key]; otherwise, <c>false</c>.
/// </returns>
public bool Contains(string key)
{
lock (_sync)
{
if (_myStore.DirectoryExists(key) && GetFileNames(key).Any())
{
string currentFile = GetFileNames(key).FirstOrDefault();
if (currentFile != null)
{
var expirationDate =
DateTime.FromFileTimeUtc(long.Parse(Path.GetFileNameWithoutExtension(currentFile)));
if (expirationDate >= DateTime.UtcNow)
return true;
}
}
return false;
}
}
/// <summary>
/// Removes the specified key.
/// </summary>
/// <param name="key">The key.</param>
public void Remove(string key)
{
lock (_sync)
{
if (!Contains(key))
throw new AccessViolationException("The key does not exist in the cache");
string currentFile = GetFileNames(key).FirstOrDefault();
if (currentFile != null)
_myStore.DeleteFile(string.Format("{0}\\{1}", key, currentFile));
_myStore.DeleteDirectory(key);
}
}
/// <summary>
/// Gets the file names.
/// </summary>
/// <param name="key">The key.</param>
/// <returns></returns>
private IEnumerable<string> GetFileNames(string key)
{
return _myStore.GetFileNames(string.Format("{0}\\*.cache", key));
}
/// <summary>
/// Gets the specified key.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key">The key.</param>
/// <returns></returns>
public T Get<T>(string key)
{
lock (_sync)
{
string currentFile = GetFileNames(key).FirstOrDefault();
if (currentFile != null)
{
var expirationDate =
DateTime.FromFileTimeUtc(long.Parse(Path.GetFileNameWithoutExtension(currentFile)));
if (expirationDate >= DateTime.UtcNow)
{
return NormalRead<T>(string.Format(@"{0}\{1}", key, currentFile));
}
Remove(key);
}
return default(T);
}
}
#region Serialization
private T NormalRead<T>(string fileName)
{
using (var isolatedStorageFileStream = new IsolatedStorageFileStream(fileName, FileMode.Open, _myStore))
{
DataContractSerializer s = new DataContractSerializer(typeof(T));
var value = s.ReadObject(isolatedStorageFileStream);
isolatedStorageFileStream.Close();
return (T)value;
}
}
private void NormalWrite(string fileName, object value)
{
using (var isolatedStorageFileStream = new IsolatedStorageFileStream(fileName, FileMode.OpenOrCreate, _myStore))
{
DataContractSerializer s = new DataContractSerializer(value.GetType());
s.WriteObject(isolatedStorageFileStream, value);
}
}
#endregion
}
}
+117
View File
@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>10.0.20506</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{B55A0F90-2B5A-4C4B-88F4-013AA1629866}</ProjectGuid>
<ProjectTypeGuids>{C089C8C0-30E0-4E22-80C0-CE093F111A43};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Phone7.Fx.Preview</RootNamespace>
<AssemblyName>Phone7.Fx.Preview</AssemblyName>
<TargetFrameworkVersion>v8.0</TargetFrameworkVersion>
<SilverlightVersion>
</SilverlightVersion>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<TargetFrameworkIdentifier>WindowsPhone</TargetFrameworkIdentifier>
<SilverlightApplication>false</SilverlightApplication>
<ValidateXaml>true</ValidateXaml>
<ThrowErrorsInValidation>true</ThrowErrorsInValidation>
<FileUpgradeFlags>
</FileUpgradeFlags>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<OldToolsVersion>4.0</OldToolsVersion>
<MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>Bin\Debug</OutputPath>
<DefineConstants>DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>Bin\Release</OutputPath>
<DefineConstants>TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<PlatformTarget />
<OutputPath>Bin\x86\Debug</OutputPath>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<PlatformTarget />
<OutputPath>Bin\x86\Release</OutputPath>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
<PlatformTarget />
<OutputPath>Bin\ARM\Debug</OutputPath>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
<PlatformTarget />
<OutputPath>Bin\ARM\Release</OutputPath>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
</PropertyGroup>
<ItemGroup>
<Compile Include="BindableApplicationBar.xaml.cs" />
<Compile Include="BindableApplicationBarIconButton.xaml.cs" />
<Compile Include="BindableApplicationBarMenuItem.xaml.cs" />
<Compile Include="Cache.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="VisualTreeHelperExtensions.cs" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\$(TargetFrameworkIdentifier)\$(TargetFrameworkVersion)\Microsoft.$(TargetFrameworkIdentifier).$(TargetFrameworkVersion).Overrides.targets" />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\$(TargetFrameworkIdentifier)\$(TargetFrameworkVersion)\Microsoft.$(TargetFrameworkIdentifier).CSharp.targets" />
<ProjectExtensions />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
@@ -0,0 +1,35 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Phone7.Fx.Preview")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft")]
[assembly: AssemblyProduct("Phone7.Fx.Preview")]
[assembly: AssemblyCopyright("Copyright © Microsoft 2010")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("f2bd3027-1a6d-4c83-9434-4ad1349fd608")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
@@ -0,0 +1,394 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Media;
namespace Phone7.Fx.Preview
{
public static class VisualTreeHelperExtensions
{
/// <summary>
/// Equivalent of FindName, but works on the visual tree to go through templates, etc.
/// </summary>
/// <param name="root">The node to search from</param>
/// <param name="name">The name to look for</param>
/// <returns>The found node, or null if not found</returns>
public static FrameworkElement FindVisualChild(this FrameworkElement root, string name)
{
FrameworkElement temp = root.FindName(name) as FrameworkElement;
if (temp != null)
return temp;
foreach (FrameworkElement element in root.GetVisualChildren())
{
temp = element.FindName(name) as FrameworkElement;
if (temp != null)
return temp;
}
return null;
}
/// <summary>
/// Gets the visual parent of the element
/// </summary>
/// <param name="node">The element to check</param>
/// <returns>The visual parent</returns>
public static FrameworkElement GetVisualParent(this FrameworkElement node)
{
return VisualTreeHelper.GetParent(node) as FrameworkElement;
}
/// <summary>
/// Gets a visual child of the element
/// </summary>
/// <param name="node">The element to check</param>
/// <param name="index">The index of the child</param>
/// <returns>The found child</returns>
public static FrameworkElement GetVisualChild(this FrameworkElement node, int index)
{
return VisualTreeHelper.GetChild(node, index) as FrameworkElement;
}
/// <summary>
/// Gets all the visual children of the element
/// </summary>
/// <param name="root">The element to get children of</param>
/// <returns>An enumerator of the children</returns>
public static IEnumerable<FrameworkElement> GetVisualChildren(this FrameworkElement root)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(root); i++)
yield return VisualTreeHelper.GetChild(root, i) as FrameworkElement;
}
/// <summary>
/// Gets the ancestors of the element, up to the root
/// </summary>
/// <param name="node">The element to start from</param>
/// <returns>An enumerator of the ancestors</returns>
public static IEnumerable<FrameworkElement> GetVisualAncestors(this FrameworkElement node)
{
FrameworkElement parent = node.GetVisualParent();
while (parent != null)
{
yield return parent;
parent = parent.GetVisualParent();
}
}
/// <summary>
/// Gets the VisualStateGroup with the given name, looking up the visual tree
/// </summary>
/// <param name="root">Element to start from</param>
/// <param name="groupName">Name of the group to look for</param>
/// <param name="searchAncestors">Whether or not to look up the tree</param>
/// <returns>The group, if found</returns>
public static VisualStateGroup GetVisualStateGroup(this FrameworkElement root, string groupName, bool searchAncestors)
{
IList groups = VisualStateManager.GetVisualStateGroups(root);
foreach (object o in groups)
{
VisualStateGroup group = o as VisualStateGroup;
if (group != null && group.Name == groupName)
return group;
}
if (searchAncestors)
{
FrameworkElement parent = root.GetVisualParent();
if (parent != null)
return parent.GetVisualStateGroup(groupName, true);
}
return null;
}
/// <summary>
/// Finds the VisualStateGroup with the given name
/// </summary>
/// <param name="root">The root.</param>
/// <param name="name">The name.</param>
/// <returns></returns>
public static VisualStateGroup FindVisualState(this FrameworkElement root, string name)
{
if (root == null)
return null;
IList groups = VisualStateManager.GetVisualStateGroups(root);
return groups.Cast<VisualStateGroup>().FirstOrDefault(group => group.Name == name);
}
/// <summary>
/// Performs a breadth-first enumeration of all the descendents in the tree
/// </summary>
/// <param name="root">The root node</param>
/// <returns>An enumerator of all the children</returns>
public static IEnumerable<FrameworkElement> GetVisualDescendents(this FrameworkElement root)
{
Queue<IEnumerable<FrameworkElement>> toDo = new Queue<IEnumerable<FrameworkElement>>();
toDo.Enqueue(root.GetVisualChildren());
while (toDo.Count > 0)
{
IEnumerable<FrameworkElement> children = toDo.Dequeue();
foreach (FrameworkElement child in children)
{
yield return child;
toDo.Enqueue(child.GetVisualChildren());
}
}
}
/// <summary>
/// Provides a debug string that represents the visual child tree
/// </summary>
/// <param name="root">The root node</param>
/// <param name="result">StringBuilder into which the text is appended</param>
/// <remarks>This method only works in DEBUG mode</remarks>
[Conditional("DEBUG")]
public static void GetVisualChildTreeDebugText(this FrameworkElement root, StringBuilder result)
{
List<string> results = new List<string>();
root.GetChildTree("", " ", results);
foreach (string s in results)
result.AppendLine(s);
}
private static void GetChildTree(this FrameworkElement root, string prefix, string addPrefix, List<string> results)
{
string thisElement = "";
if (String.IsNullOrEmpty(root.Name))
thisElement = "[Anonymous]";
else
thisElement = string.Format("[{0}]", root.Name);
thisElement += string.Format(" : {0}", root.GetType().Name);
results.Add(prefix + thisElement);
foreach (FrameworkElement directChild in root.GetVisualChildren())
{
directChild.GetChildTree(prefix + addPrefix, addPrefix, results);
}
}
/// <summary>
/// Provides a debug string that represents the visual child tree
/// </summary>
/// <param name="node">The root node</param>
/// <param name="result">StringBuilder into which the text is appended</param>
/// <remarks>This method only works in DEBUG mode</remarks>
[Conditional("DEBUG")]
public static void GetAncestorVisualTreeDebugText(this FrameworkElement node, StringBuilder result)
{
List<string> tree = new List<string>();
node.GetAncestorVisualTree(tree);
string prefix = "";
foreach (string s in tree)
{
result.AppendLine(prefix + s);
prefix = prefix + " ";
}
}
private static void GetAncestorVisualTree(this FrameworkElement node, List<string> children)
{
string name = String.IsNullOrEmpty(node.Name) ? "[Anon]" : node.Name;
string thisNode = name + ": " + node.GetType().Name;
// Ensure list is in reverse order going up the tree
children.Insert(0, thisNode);
FrameworkElement parent = node.GetVisualParent();
if (parent != null)
GetAncestorVisualTree(parent, children);
}
/// <summary>
/// Returns a render transform of the specified type from the element, creating it if necessary
/// </summary>
/// <typeparam name="TRequestedTransform">The type of transform (Rotate, Translate, etc)</typeparam>
/// <param name="element">The element to check</param>
/// <param name="mode">The mode to use for creating transforms, if not found</param>
/// <returns>The specified transform, or null if not found and not created</returns>
public static TRequestedTransform GetTransform<TRequestedTransform>(this UIElement element, TransformCreationMode mode) where TRequestedTransform : Transform, new()
{
Transform originalTransform = element.RenderTransform;
TRequestedTransform requestedTransform = null;
MatrixTransform matrixTransform = null;
TransformGroup transformGroup = null;
// Current transform is null -- create if necessary and return
if (originalTransform == null)
{
if ((mode & TransformCreationMode.Create) == TransformCreationMode.Create)
{
requestedTransform = new TRequestedTransform();
element.RenderTransform = requestedTransform;
return requestedTransform;
}
return null;
}
// Transform is exactly what we want -- return it
requestedTransform = originalTransform as TRequestedTransform;
if (requestedTransform != null)
return requestedTransform;
// The existing transform is matrix transform - overwrite if necessary and return
matrixTransform = originalTransform as MatrixTransform;
if (matrixTransform != null)
{
if (matrixTransform.Matrix.IsIdentity
&& (mode & TransformCreationMode.Create) == TransformCreationMode.Create
&& (mode & TransformCreationMode.IgnoreIdentityMatrix) == TransformCreationMode.IgnoreIdentityMatrix)
{
requestedTransform = new TRequestedTransform();
element.RenderTransform = requestedTransform;
return requestedTransform;
}
return null;
}
// Transform is actually a group -- check for the requested type
transformGroup = originalTransform as TransformGroup;
if (transformGroup != null)
{
foreach (Transform child in transformGroup.Children)
{
// Child is the right type -- return it
if (child is TRequestedTransform)
return child as TRequestedTransform;
}
// Right type was not found, but we are OK to add it
if ((mode & TransformCreationMode.AddToGroup) == TransformCreationMode.AddToGroup)
{
requestedTransform = new TRequestedTransform();
transformGroup.Children.Add(requestedTransform);
return requestedTransform;
}
return null;
}
// Current ransform is not a group and is not what we want;
// create a new group containing the existing transform and the new one
if ((mode & TransformCreationMode.CombineIntoGroup) == TransformCreationMode.CombineIntoGroup)
{
transformGroup = new TransformGroup();
transformGroup.Children.Add(originalTransform);
transformGroup.Children.Add(requestedTransform);
element.RenderTransform = transformGroup;
return requestedTransform;
}
Debug.Assert(false, "Shouldn't get here");
return null;
}
/// <summary>
/// Returns a string representation of a property path needed to update a Storyboard
/// </summary>
/// <param name="element">The element to get the path for</param>
/// <param name="subProperty">The property of the transform</param>
/// <typeparam name="TRequestedType">The type of transform to look fo</typeparam>
/// <returns>A property path</returns>
public static string GetTransformPropertyPath<TRequestedType>(this FrameworkElement element, string subProperty) where TRequestedType : Transform
{
Transform t = element.RenderTransform;
if (t is TRequestedType)
return String.Format("(RenderTransform).({0}.{1})", typeof(TRequestedType).Name, subProperty);
else if (t is TransformGroup)
{
TransformGroup g = t as TransformGroup;
for (int i = 0; i < g.Children.Count; i++)
{
if (g.Children[i] is TRequestedType)
return String.Format("(RenderTransform).(TransformGroup.Children)[" + i + "].({0}.{1})",
typeof(TRequestedType).Name, subProperty);
}
}
return "";
}
/// <summary>
/// Returns a plane projection, creating it if necessary
/// </summary>
/// <param name="element">The element</param>
/// <param name="create">Whether or not to create the projection if it doesn't already exist</param>
/// <returns>The plane project, or null if not found / created</returns>
public static PlaneProjection GetPlaneProjection(this UIElement element, bool create)
{
Projection originalProjection = element.Projection;
PlaneProjection projection = null;
// Projection is already a plane projection; return it
if (originalProjection is PlaneProjection)
return originalProjection as PlaneProjection;
// Projection is null; create it if necessary
if (originalProjection == null)
{
if (create)
{
projection = new PlaneProjection();
element.Projection = projection;
}
}
// Note that if the project is a Matrix projection, it will not be
// changed and null will be returned.
return projection;
}
}
/// <summary>
/// Possible modes for creating a transform
/// </summary>
[Flags]
public enum TransformCreationMode
{
/// <summary>
/// Don't try and create a transform if it doesn't already exist
/// </summary>
None = 0,
/// <summary>
/// Create a transform if none exists
/// </summary>
Create = 1,
/// <summary>
/// Create and add to an existing group
/// </summary>
AddToGroup = 2,
/// <summary>
/// Create a group and combine with existing transform; may break existing animations
/// </summary>
CombineIntoGroup = 4,
/// <summary>
/// Treat identity matrix as if it wasn't there; may break existing animations
/// </summary>
IgnoreIdentityMatrix = 8,
/// <summary>
/// Create a new transform or add to group
/// </summary>
CreateOrAddAndIgnoreMatrix = Create | AddToGroup | IgnoreIdentityMatrix,
/// <summary>
/// Default behaviour, equivalent to CreateOrAddAndIgnoreMatrix
/// </summary>
Default = CreateOrAddAndIgnoreMatrix,
}
}