diff --git a/main/Libs/Phone7.Fx.Preview/BindableApplicationBar.xaml.cs b/main/Libs/Phone7.Fx.Preview/BindableApplicationBar.xaml.cs new file mode 100644 index 0000000..da98e0f --- /dev/null +++ b/main/Libs/Phone7.Fx.Preview/BindableApplicationBar.xaml.cs @@ -0,0 +1,111 @@ +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 IList Buttons + { + get { return this.Items; } + + } + + public IList MenuItems + { + get { return this.Items; } + } + + public event EventHandler StateChanged; + } +} \ No newline at end of file diff --git a/main/Libs/Phone7.Fx.Preview/BindableApplicationBarIconButton.xaml.cs b/main/Libs/Phone7.Fx.Preview/BindableApplicationBarIconButton.xaml.cs new file mode 100644 index 0000000..ded5c40 --- /dev/null +++ b/main/Libs/Phone7.Fx.Preview/BindableApplicationBarIconButton.xaml.cs @@ -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; } + } + } +} \ No newline at end of file diff --git a/main/Libs/Phone7.Fx.Preview/BindableApplicationBarMenuItem.xaml.cs b/main/Libs/Phone7.Fx.Preview/BindableApplicationBarMenuItem.xaml.cs new file mode 100644 index 0000000..899ea38 --- /dev/null +++ b/main/Libs/Phone7.Fx.Preview/BindableApplicationBarMenuItem.xaml.cs @@ -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; + + + } +} \ No newline at end of file diff --git a/main/Libs/Phone7.Fx.Preview/Cache.cs b/main/Libs/Phone7.Fx.Preview/Cache.cs new file mode 100644 index 0000000..039dd07 --- /dev/null +++ b/main/Libs/Phone7.Fx.Preview/Cache.cs @@ -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 +{ + /// + /// + /// + 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; + /// + /// Gets the current instance of the cache + /// + /// The current. + public static Cache Current + { + get { return _current ?? (_current = new Cache()); } + } + + /// + /// Adds the specified key. + /// + /// The key. + /// The value. + /// The absolute expiration. + /// The sliding expiration. + 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); + } + } + + /// + /// Adds the specified key. + /// + /// The key. + /// The expiration date. + /// The value. + 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); + } + + } + + /// + /// Determines whether the cache contains the specified key. + /// + /// The key. + /// + /// true if [contains] [the specified key]; otherwise, false. + /// + 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; + } + } + + /// + /// Removes the specified key. + /// + /// The key. + 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); + } + } + + /// + /// Gets the file names. + /// + /// The key. + /// + private IEnumerable GetFileNames(string key) + { + return _myStore.GetFileNames(string.Format("{0}\\*.cache", key)); + } + + /// + /// Gets the specified key. + /// + /// + /// The key. + /// + public T Get(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(string.Format(@"{0}\{1}", key, currentFile)); + } + Remove(key); + } + return default(T); + } + + } + + #region Serialization + + private T NormalRead(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 + } +} \ No newline at end of file diff --git a/main/Libs/Phone7.Fx.Preview/Phone7.Fx.Preview.csproj b/main/Libs/Phone7.Fx.Preview/Phone7.Fx.Preview.csproj new file mode 100644 index 0000000..c47b718 --- /dev/null +++ b/main/Libs/Phone7.Fx.Preview/Phone7.Fx.Preview.csproj @@ -0,0 +1,72 @@ + + + + Debug + AnyCPU + 10.0.20506 + 2.0 + {B55A0F90-2B5A-4C4B-88F4-013AA1629866} + {C089C8C0-30E0-4E22-80C0-CE093F111A43};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + Phone7.Fx.Preview + Phone7.Fx.Preview + v4.0 + $(TargetFrameworkVersion) + WindowsPhone + Silverlight + false + true + true + + + true + full + false + Bin\Debug + DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE + true + true + prompt + 4 + + + pdbonly + true + Bin\Release + TRACE;SILVERLIGHT;WINDOWS_PHONE + true + true + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/main/Libs/Phone7.Fx.Preview/Properties/AssemblyInfo.cs b/main/Libs/Phone7.Fx.Preview/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..cecc55a --- /dev/null +++ b/main/Libs/Phone7.Fx.Preview/Properties/AssemblyInfo.cs @@ -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")] diff --git a/main/Libs/Phone7.Fx.Preview/VisualTreeHelperExtensions.cs b/main/Libs/Phone7.Fx.Preview/VisualTreeHelperExtensions.cs new file mode 100644 index 0000000..022cab7 --- /dev/null +++ b/main/Libs/Phone7.Fx.Preview/VisualTreeHelperExtensions.cs @@ -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 + { + /// + /// Equivalent of FindName, but works on the visual tree to go through templates, etc. + /// + /// The node to search from + /// The name to look for + /// The found node, or null if not found + 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; + } + + /// + /// Gets the visual parent of the element + /// + /// The element to check + /// The visual parent + public static FrameworkElement GetVisualParent(this FrameworkElement node) + { + return VisualTreeHelper.GetParent(node) as FrameworkElement; + } + + /// + /// Gets a visual child of the element + /// + /// The element to check + /// The index of the child + /// The found child + public static FrameworkElement GetVisualChild(this FrameworkElement node, int index) + { + return VisualTreeHelper.GetChild(node, index) as FrameworkElement; + } + + /// + /// Gets all the visual children of the element + /// + /// The element to get children of + /// An enumerator of the children + public static IEnumerable GetVisualChildren(this FrameworkElement root) + { + for (int i = 0; i < VisualTreeHelper.GetChildrenCount(root); i++) + yield return VisualTreeHelper.GetChild(root, i) as FrameworkElement; + } + + /// + /// Gets the ancestors of the element, up to the root + /// + /// The element to start from + /// An enumerator of the ancestors + public static IEnumerable GetVisualAncestors(this FrameworkElement node) + { + FrameworkElement parent = node.GetVisualParent(); + while (parent != null) + { + yield return parent; + parent = parent.GetVisualParent(); + } + } + + /// + /// Gets the VisualStateGroup with the given name, looking up the visual tree + /// + /// Element to start from + /// Name of the group to look for + /// Whether or not to look up the tree + /// The group, if found + 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; + } + + /// + /// Finds the VisualStateGroup with the given name + /// + /// The root. + /// The name. + /// + public static VisualStateGroup FindVisualState(this FrameworkElement root, string name) + { + if (root == null) + return null; + + IList groups = VisualStateManager.GetVisualStateGroups(root); + return groups.Cast().FirstOrDefault(group => group.Name == name); + } + + /// + /// Performs a breadth-first enumeration of all the descendents in the tree + /// + /// The root node + /// An enumerator of all the children + public static IEnumerable GetVisualDescendents(this FrameworkElement root) + { + Queue> toDo = new Queue>(); + + toDo.Enqueue(root.GetVisualChildren()); + while (toDo.Count > 0) + { + IEnumerable children = toDo.Dequeue(); + foreach (FrameworkElement child in children) + { + yield return child; + toDo.Enqueue(child.GetVisualChildren()); + } + } + } + + /// + /// Provides a debug string that represents the visual child tree + /// + /// The root node + /// StringBuilder into which the text is appended + /// This method only works in DEBUG mode + [Conditional("DEBUG")] + public static void GetVisualChildTreeDebugText(this FrameworkElement root, StringBuilder result) + { + List results = new List(); + root.GetChildTree("", " ", results); + foreach (string s in results) + result.AppendLine(s); + } + + private static void GetChildTree(this FrameworkElement root, string prefix, string addPrefix, List 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); + } + } + + /// + /// Provides a debug string that represents the visual child tree + /// + /// The root node + /// StringBuilder into which the text is appended + /// This method only works in DEBUG mode + [Conditional("DEBUG")] + public static void GetAncestorVisualTreeDebugText(this FrameworkElement node, StringBuilder result) + { + List tree = new List(); + node.GetAncestorVisualTree(tree); + string prefix = ""; + foreach (string s in tree) + { + result.AppendLine(prefix + s); + prefix = prefix + " "; + } + } + + private static void GetAncestorVisualTree(this FrameworkElement node, List 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); + } + + /// + /// Returns a render transform of the specified type from the element, creating it if necessary + /// + /// The type of transform (Rotate, Translate, etc) + /// The element to check + /// The mode to use for creating transforms, if not found + /// The specified transform, or null if not found and not created + public static TRequestedTransform GetTransform(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; + } + + /// + /// Returns a string representation of a property path needed to update a Storyboard + /// + /// The element to get the path for + /// The property of the transform + /// The type of transform to look fo + /// A property path + public static string GetTransformPropertyPath(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 ""; + } + + /// + /// Returns a plane projection, creating it if necessary + /// + /// The element + /// Whether or not to create the projection if it doesn't already exist + /// The plane project, or null if not found / created + 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; + } + } + + /// + /// Possible modes for creating a transform + /// + [Flags] + public enum TransformCreationMode + { + /// + /// Don't try and create a transform if it doesn't already exist + /// + None = 0, + + /// + /// Create a transform if none exists + /// + Create = 1, + + /// + /// Create and add to an existing group + /// + AddToGroup = 2, + + /// + /// Create a group and combine with existing transform; may break existing animations + /// + CombineIntoGroup = 4, + + /// + /// Treat identity matrix as if it wasn't there; may break existing animations + /// + IgnoreIdentityMatrix = 8, + + /// + /// Create a new transform or add to group + /// + CreateOrAddAndIgnoreMatrix = Create | AddToGroup | IgnoreIdentityMatrix, + + /// + /// Default behaviour, equivalent to CreateOrAddAndIgnoreMatrix + /// + Default = CreateOrAddAndIgnoreMatrix, + } +} \ No newline at end of file diff --git a/main/MyFriendsAround.WP7/MainPage.xaml b/main/MyFriendsAround.WP7/MainPage.xaml index aecae21..e5778b1 100644 --- a/main/MyFriendsAround.WP7/MainPage.xaml +++ b/main/MyFriendsAround.WP7/MainPage.xaml @@ -1,4 +1,4 @@ - + xmlns:my="clr-namespace:Microsoft.Phone.Controls.Maps;assembly=Microsoft.Phone.Controls.Maps" xmlns:Preview="clr-namespace:Phone7.Fx.Preview;assembly=Phone7.Fx.Preview"> @@ -50,30 +50,36 @@ + Grid.Row="1" + Margin="0,0,0,70"> -