diff --git a/PropertyDependencyDemo/Droid/Assets/AboutAssets.txt b/PropertyDependencyDemo/Droid/Assets/AboutAssets.txt new file mode 100644 index 0000000..a9b0638 --- /dev/null +++ b/PropertyDependencyDemo/Droid/Assets/AboutAssets.txt @@ -0,0 +1,19 @@ +Any raw assets you want to be deployed with your application can be placed in +this directory (and child directories) and given a Build Action of "AndroidAsset". + +These files will be deployed with your package and will be accessible using Android's +AssetManager, like this: + +public class ReadAsset : Activity +{ + protected override void OnCreate (Bundle bundle) + { + base.OnCreate (bundle); + + InputStream input = Assets.Open ("my_asset.txt"); + } +} + +Additionally, some Android functions will automatically load asset files: + +Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf"); diff --git a/PropertyDependencyDemo/Droid/MainActivity.cs b/PropertyDependencyDemo/Droid/MainActivity.cs new file mode 100644 index 0000000..b5b710b --- /dev/null +++ b/PropertyDependencyDemo/Droid/MainActivity.cs @@ -0,0 +1,26 @@ +using System; + +using Android.App; +using Android.Content; +using Android.Content.PM; +using Android.Runtime; +using Android.Views; +using Android.Widget; +using Android.OS; + +namespace PropertyDependencyDemo.Droid +{ + [Activity (Label = "PropertyDependencyDemo.Droid", Icon = "@drawable/icon", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)] + public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity + { + protected override void OnCreate (Bundle bundle) + { + base.OnCreate (bundle); + + global::Xamarin.Forms.Forms.Init (this, bundle); + + LoadApplication (new App ()); + } + } +} + diff --git a/PropertyDependencyDemo/Droid/Properties/AndroidManifest.xml b/PropertyDependencyDemo/Droid/Properties/AndroidManifest.xml new file mode 100644 index 0000000..9b7ac98 --- /dev/null +++ b/PropertyDependencyDemo/Droid/Properties/AndroidManifest.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/PropertyDependencyDemo/Droid/Properties/AssemblyInfo.cs b/PropertyDependencyDemo/Droid/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..4694bb5 --- /dev/null +++ b/PropertyDependencyDemo/Droid/Properties/AssemblyInfo.cs @@ -0,0 +1,28 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using Android.App; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle ("PropertyDependencyDemo.Droid")] +[assembly: AssemblyDescription ("")] +[assembly: AssemblyConfiguration ("")] +[assembly: AssemblyCompany ("Wintellect, LLC")] +[assembly: AssemblyProduct ("")] +[assembly: AssemblyCopyright ("2015 Wintellect, LLC")] +[assembly: AssemblyTrademark ("")] +[assembly: AssemblyCulture ("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion ("1.0.0")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/PropertyDependencyDemo/Droid/PropertyDependencyDemo.Droid.csproj b/PropertyDependencyDemo/Droid/PropertyDependencyDemo.Droid.csproj new file mode 100644 index 0000000..82bb620 --- /dev/null +++ b/PropertyDependencyDemo/Droid/PropertyDependencyDemo.Droid.csproj @@ -0,0 +1,93 @@ + + + + Debug + AnyCPU + {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + {932823BE-C1C5-475D-A752-15EBDBAC6A63} + Library + PropertyDependencyDemo.Droid + Assets + Resources + Properties\AndroidManifest.xml + Resource + Resources\Resource.designer.cs + True + True + PropertyDependencyDemo.Droid + v6.0 + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + None + false + + + full + true + bin\Release + prompt + 4 + false + false + + + + + + + + ..\packages\Xamarin.Forms.1.5.0.6447\lib\MonoAndroid10\Xamarin.Forms.Platform.Android.dll + + + ..\packages\Xamarin.Forms.1.5.0.6447\lib\MonoAndroid10\FormsViewGroup.dll + + + ..\packages\Xamarin.Forms.1.5.0.6447\lib\MonoAndroid10\Xamarin.Forms.Core.dll + + + ..\packages\Xamarin.Forms.1.5.0.6447\lib\MonoAndroid10\Xamarin.Forms.Xaml.dll + + + ..\packages\Xamarin.Forms.1.5.0.6447\lib\MonoAndroid10\Xamarin.Forms.Platform.dll + + + ..\packages\Xamarin.Android.Support.v4.23.0.1.3\lib\MonoAndroid403\Xamarin.Android.Support.v4.dll + + + + + {62CB0D3F-DD9D-4CEC-A286-6BDC4B31B726} + PropertyDependencyDemo + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/PropertyDependencyDemo/Droid/Resources/AboutResources.txt b/PropertyDependencyDemo/Droid/Resources/AboutResources.txt new file mode 100644 index 0000000..10f52d4 --- /dev/null +++ b/PropertyDependencyDemo/Droid/Resources/AboutResources.txt @@ -0,0 +1,44 @@ +Images, layout descriptions, binary blobs and string dictionaries can be included +in your application as resource files. Various Android APIs are designed to +operate on the resource IDs instead of dealing with images, strings or binary blobs +directly. + +For example, a sample Android app that contains a user interface layout (main.axml), +an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png) +would keep its resources in the "Resources" directory of the application: + +Resources/ + drawable/ + icon.png + + layout/ + main.axml + + values/ + strings.xml + +In order to get the build system to recognize Android resources, set the build action to +"AndroidResource". The native Android APIs do not operate directly with filenames, but +instead operate on resource IDs. When you compile an Android application that uses resources, +the build system will package the resources for distribution and generate a class called "R" +(this is an Android convention) that contains the tokens for each one of the resources +included. For example, for the above Resources layout, this is what the R class would expose: + +public class R { + public class drawable { + public const int icon = 0x123; + } + + public class layout { + public const int main = 0x456; + } + + public class strings { + public const int first_string = 0xabc; + public const int second_string = 0xbcd; + } +} + +You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main +to reference the layout/main.axml file, or R.strings.first_string to reference the first +string in the dictionary file values/strings.xml. diff --git a/PropertyDependencyDemo/Droid/Resources/Resource.designer.cs b/PropertyDependencyDemo/Droid/Resources/Resource.designer.cs new file mode 100644 index 0000000..94e5ae2 --- /dev/null +++ b/PropertyDependencyDemo/Droid/Resources/Resource.designer.cs @@ -0,0 +1,61 @@ +#pragma warning disable 1591 +// ------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Mono Runtime Version: 4.0.30319.17020 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ + +[assembly: Android.Runtime.ResourceDesignerAttribute("PropertyDependencyDemo.Droid.Resource", IsApplication=true)] + +namespace PropertyDependencyDemo.Droid +{ + + + [System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")] + public partial class Resource + { + + static Resource() + { + global::Android.Runtime.ResourceIdManager.UpdateIdValues(); + } + + public static void UpdateIdValues() + { + } + + public partial class Attribute + { + + static Attribute() + { + global::Android.Runtime.ResourceIdManager.UpdateIdValues(); + } + + private Attribute() + { + } + } + + public partial class Drawable + { + + // aapt resource value: 0x7f020000 + public const int icon = 2130837504; + + static Drawable() + { + global::Android.Runtime.ResourceIdManager.UpdateIdValues(); + } + + private Drawable() + { + } + } + } +} +#pragma warning restore 1591 diff --git a/PropertyDependencyDemo/Droid/Resources/drawable-hdpi/icon.png b/PropertyDependencyDemo/Droid/Resources/drawable-hdpi/icon.png new file mode 100644 index 0000000..964f110 Binary files /dev/null and b/PropertyDependencyDemo/Droid/Resources/drawable-hdpi/icon.png differ diff --git a/PropertyDependencyDemo/Droid/Resources/drawable-xhdpi/icon.png b/PropertyDependencyDemo/Droid/Resources/drawable-xhdpi/icon.png new file mode 100644 index 0000000..3c01e60 Binary files /dev/null and b/PropertyDependencyDemo/Droid/Resources/drawable-xhdpi/icon.png differ diff --git a/PropertyDependencyDemo/Droid/Resources/drawable-xxhdpi/icon.png b/PropertyDependencyDemo/Droid/Resources/drawable-xxhdpi/icon.png new file mode 100644 index 0000000..0d8c1c5 Binary files /dev/null and b/PropertyDependencyDemo/Droid/Resources/drawable-xxhdpi/icon.png differ diff --git a/PropertyDependencyDemo/Droid/Resources/drawable/icon.png b/PropertyDependencyDemo/Droid/Resources/drawable/icon.png new file mode 100644 index 0000000..b0ba715 Binary files /dev/null and b/PropertyDependencyDemo/Droid/Resources/drawable/icon.png differ diff --git a/PropertyDependencyDemo/Droid/packages.config b/PropertyDependencyDemo/Droid/packages.config new file mode 100644 index 0000000..a2acf46 --- /dev/null +++ b/PropertyDependencyDemo/Droid/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/PropertyDependencyDemo/PropertyDependencyDemo.sln b/PropertyDependencyDemo/PropertyDependencyDemo.sln new file mode 100644 index 0000000..acf3bde --- /dev/null +++ b/PropertyDependencyDemo/PropertyDependencyDemo.sln @@ -0,0 +1,71 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PropertyDependencyDemo", "PropertyDependencyDemo\PropertyDependencyDemo.csproj", "{62CB0D3F-DD9D-4CEC-A286-6BDC4B31B726}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PropertyDependencyDemo.iOS", "iOS\PropertyDependencyDemo.iOS.csproj", "{5CB65EC5-5533-4E4A-B31C-F4320A648341}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PropertyDependencyDemo.Droid", "Droid\PropertyDependencyDemo.Droid.csproj", "{932823BE-C1C5-475D-A752-15EBDBAC6A63}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PropertyDependencyDemo.UITests", "UITests\PropertyDependencyDemo.UITests.csproj", "{9672DE6E-A5F8-41FF-8250-E341ABFAEBFB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + Debug|iPhoneSimulator = Debug|iPhoneSimulator + Release|iPhone = Release|iPhone + Release|iPhoneSimulator = Release|iPhoneSimulator + Debug|iPhone = Debug|iPhone + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5CB65EC5-5533-4E4A-B31C-F4320A648341}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator + {5CB65EC5-5533-4E4A-B31C-F4320A648341}.Debug|Any CPU.Build.0 = Debug|iPhoneSimulator + {5CB65EC5-5533-4E4A-B31C-F4320A648341}.Debug|iPhone.ActiveCfg = Debug|iPhone + {5CB65EC5-5533-4E4A-B31C-F4320A648341}.Debug|iPhone.Build.0 = Debug|iPhone + {5CB65EC5-5533-4E4A-B31C-F4320A648341}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator + {5CB65EC5-5533-4E4A-B31C-F4320A648341}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator + {5CB65EC5-5533-4E4A-B31C-F4320A648341}.Release|Any CPU.ActiveCfg = Release|iPhone + {5CB65EC5-5533-4E4A-B31C-F4320A648341}.Release|Any CPU.Build.0 = Release|iPhone + {5CB65EC5-5533-4E4A-B31C-F4320A648341}.Release|iPhone.ActiveCfg = Release|iPhone + {5CB65EC5-5533-4E4A-B31C-F4320A648341}.Release|iPhone.Build.0 = Release|iPhone + {5CB65EC5-5533-4E4A-B31C-F4320A648341}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator + {5CB65EC5-5533-4E4A-B31C-F4320A648341}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator + {62CB0D3F-DD9D-4CEC-A286-6BDC4B31B726}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {62CB0D3F-DD9D-4CEC-A286-6BDC4B31B726}.Debug|Any CPU.Build.0 = Debug|Any CPU + {62CB0D3F-DD9D-4CEC-A286-6BDC4B31B726}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {62CB0D3F-DD9D-4CEC-A286-6BDC4B31B726}.Debug|iPhone.Build.0 = Debug|Any CPU + {62CB0D3F-DD9D-4CEC-A286-6BDC4B31B726}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {62CB0D3F-DD9D-4CEC-A286-6BDC4B31B726}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {62CB0D3F-DD9D-4CEC-A286-6BDC4B31B726}.Release|Any CPU.ActiveCfg = Release|Any CPU + {62CB0D3F-DD9D-4CEC-A286-6BDC4B31B726}.Release|Any CPU.Build.0 = Release|Any CPU + {62CB0D3F-DD9D-4CEC-A286-6BDC4B31B726}.Release|iPhone.ActiveCfg = Release|Any CPU + {62CB0D3F-DD9D-4CEC-A286-6BDC4B31B726}.Release|iPhone.Build.0 = Release|Any CPU + {62CB0D3F-DD9D-4CEC-A286-6BDC4B31B726}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {62CB0D3F-DD9D-4CEC-A286-6BDC4B31B726}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {932823BE-C1C5-475D-A752-15EBDBAC6A63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {932823BE-C1C5-475D-A752-15EBDBAC6A63}.Debug|Any CPU.Build.0 = Debug|Any CPU + {932823BE-C1C5-475D-A752-15EBDBAC6A63}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {932823BE-C1C5-475D-A752-15EBDBAC6A63}.Debug|iPhone.Build.0 = Debug|Any CPU + {932823BE-C1C5-475D-A752-15EBDBAC6A63}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {932823BE-C1C5-475D-A752-15EBDBAC6A63}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {932823BE-C1C5-475D-A752-15EBDBAC6A63}.Release|Any CPU.ActiveCfg = Release|Any CPU + {932823BE-C1C5-475D-A752-15EBDBAC6A63}.Release|Any CPU.Build.0 = Release|Any CPU + {932823BE-C1C5-475D-A752-15EBDBAC6A63}.Release|iPhone.ActiveCfg = Release|Any CPU + {932823BE-C1C5-475D-A752-15EBDBAC6A63}.Release|iPhone.Build.0 = Release|Any CPU + {932823BE-C1C5-475D-A752-15EBDBAC6A63}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {932823BE-C1C5-475D-A752-15EBDBAC6A63}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {9672DE6E-A5F8-41FF-8250-E341ABFAEBFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9672DE6E-A5F8-41FF-8250-E341ABFAEBFB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9672DE6E-A5F8-41FF-8250-E341ABFAEBFB}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {9672DE6E-A5F8-41FF-8250-E341ABFAEBFB}.Debug|iPhone.Build.0 = Debug|Any CPU + {9672DE6E-A5F8-41FF-8250-E341ABFAEBFB}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {9672DE6E-A5F8-41FF-8250-E341ABFAEBFB}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {9672DE6E-A5F8-41FF-8250-E341ABFAEBFB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9672DE6E-A5F8-41FF-8250-E341ABFAEBFB}.Release|Any CPU.Build.0 = Release|Any CPU + {9672DE6E-A5F8-41FF-8250-E341ABFAEBFB}.Release|iPhone.ActiveCfg = Release|Any CPU + {9672DE6E-A5F8-41FF-8250-E341ABFAEBFB}.Release|iPhone.Build.0 = Release|Any CPU + {9672DE6E-A5F8-41FF-8250-E341ABFAEBFB}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {9672DE6E-A5F8-41FF-8250-E341ABFAEBFB}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/PropertyDependencyDemo/PropertyDependencyDemo/Mvvm/DelegateCommand.cs b/PropertyDependencyDemo/PropertyDependencyDemo/Mvvm/DelegateCommand.cs new file mode 100644 index 0000000..a192a1e --- /dev/null +++ b/PropertyDependencyDemo/PropertyDependencyDemo/Mvvm/DelegateCommand.cs @@ -0,0 +1,175 @@ +using System; +using System.Windows.Input; +using System.Threading.Tasks; + +namespace PropertyDependencyDemo.Mvvm +{ + /// + /// Defines an implementation wrapping an . + /// + public class DelegateCommand : ICommand + { + bool _inFlight; + readonly Func _canExecute; + readonly Action _execute; + readonly Func _task; + + /// + /// Occurs when the target of the Command should reevaluate whether or not the Command can be executed. + /// + /// + /// + public event EventHandler CanExecuteChanged; + + internal DelegateCommand(Action execute) + { + if (execute == null) + throw new ArgumentNullException("execute"); + _execute = execute; + } + + internal DelegateCommand(Action execute) + : this(o => execute()) + { + if (execute == null) + throw new ArgumentNullException("execute"); + } + + internal DelegateCommand(Func task) + : this(task, null) + { + } + + internal DelegateCommand(Func task, Func canExecute) + { + _task = task; + _canExecute = canExecute; + } + + async void InvokeCommandTask(Task commandTask) + { + _inFlight = true; + //ChangeCanExecute(); // TODO: Bug in Xamarin Forms 1.3 causes this to crash Android when command is bound to a context action + try { + await commandTask; + } finally { + _inFlight = false; + //ChangeCanExecute(); // TODO: Bug in Xamarin Forms 1.3 causes this to crash Android when command is bound to a context action + } + } + + internal DelegateCommand(Action execute, Func canExecute) + : this(execute) + { + if (canExecute == null) + throw new ArgumentNullException("canExecute"); + _canExecute = canExecute; + } + + internal DelegateCommand(Action execute, Func canExecute) + : this(o => execute(), o => canExecute()) + { + if (execute == null) + throw new ArgumentNullException("execute"); + if (canExecute == null) + throw new ArgumentNullException("canExecute"); + } + + /// An used as parameter for the execute Action. + /// + /// Invokes the execute Action + /// + /// + /// + /// + /// + /// If the Command was created with non-generic execute parameter, the parameter of this method is ignored. + /// + /// + /// + public void Execute(object parameter) + { + if (_task == null) { + _execute (parameter); + return; + } + InvokeCommandTask (_task ()); + } + + /// An used as parameter to determine if the Command can be executed. + /// + /// Returns a indicating if the Command can be exectued with the given parameter. + /// + /// + /// + /// if the Command can be executed, otherwise. + /// + /// + /// + /// + /// + /// If no canExecute parameter was passed to the Command constructor, this method always returns . + /// + /// + /// + /// If the Command was created with non-generic execute parameter, the parameter of this method is ignored. + /// + /// + /// + public bool CanExecute(object parameter) + { + if (_inFlight) + { + return false; + } + return _canExecute == null || _canExecute(parameter); + } + + /// + /// Send a + /// + /// + /// + public void ChangeCanExecute() + { + EventHandler eventHandler = CanExecuteChanged; + if (eventHandler == null) + return; + eventHandler(this, EventArgs.Empty); + } + } + + /// The Type of the parameter, + /// + /// Defines an implementation wrapping a generic Action<T>. + /// + public sealed class DelegateCommand : DelegateCommand + { + internal DelegateCommand(Action execute) + : base(o => execute((T)o)) + { + if (execute == null) + throw new ArgumentNullException("execute"); + } + + internal DelegateCommand(Func> task) + : base(task) + { + } + + internal DelegateCommand(Action execute, Func canExecute) + : base(o => execute((T)o), o => canExecute((T)o)) + { + if (execute == null) + throw new ArgumentNullException("execute"); + if (canExecute == null) + throw new ArgumentNullException("canExecute"); + } + + internal DelegateCommand(Func> task, Func canExecute) + : base(task, o => canExecute((T)o)) + { + } + } +} + diff --git a/PropertyDependencyDemo/PropertyDependencyDemo/Mvvm/LinqExtensions.cs b/PropertyDependencyDemo/PropertyDependencyDemo/Mvvm/LinqExtensions.cs new file mode 100644 index 0000000..00830d8 --- /dev/null +++ b/PropertyDependencyDemo/PropertyDependencyDemo/Mvvm/LinqExtensions.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace PropertyDependencyDemo.Mvvm +{ + public static class LinqExtensions + { + /// + /// Performs the specified action on each element of the collection. + /// + /// A collection of elements. + /// The delegate to perform on each element of the collection. + /// is null. + public static void ForEach(this IEnumerable list, Action action) + { + if (action == null) + throw new ArgumentNullException("action"); + if (list == null) + throw new ArgumentNullException("list"); + foreach (var item in list.ToList()) + action(item); + } + + /// + /// Performs a full outer join of two collections that share a common key + /// + /// Element Type of first collection + /// Element Type of second collection + /// Common Key Type + /// Resulting collection Type + /// First collection + /// Second collection + /// Key selector for first collection + /// Key selector for second collection + /// Results selector + /// Default value used when the first collection does not have a joining key + /// Default value used when the second collection does not have a joining key + /// Custom Key comparer + /// + public static IList FullOuterJoin( + this IEnumerable a, + IEnumerable b, + Func selectKeyA, + Func selectKeyB, + Func projection, + TA defaultA = default(TA), + TB defaultB = default(TB), + IEqualityComparer cmp = null) + { + cmp = cmp ?? EqualityComparer.Default; + var alookup = a.ToLookup(selectKeyA, cmp); + var blookup = b.ToLookup(selectKeyB, cmp); + + var keys = new HashSet(alookup.Select(p => p.Key), cmp); + keys.UnionWith(blookup.Select(p => p.Key)); + + var join = from key in keys + from xa in alookup[key].DefaultIfEmpty(defaultA) + from xb in blookup[key].DefaultIfEmpty(defaultB) + select projection(xa, xb, key); + + return join.ToList(); + } + } +} + diff --git a/PropertyDependencyDemo/PropertyDependencyDemo/Mvvm/ObservableExtensions.cs b/PropertyDependencyDemo/PropertyDependencyDemo/Mvvm/ObservableExtensions.cs new file mode 100644 index 0000000..50639ad --- /dev/null +++ b/PropertyDependencyDemo/PropertyDependencyDemo/Mvvm/ObservableExtensions.cs @@ -0,0 +1,24 @@ +using System; +using System.ComponentModel; +using System.Linq.Expressions; + +namespace PropertyDependencyDemo.Mvvm +{ + public static class ObservableExtensions + { + /// + /// Monitors an observable object for property change events. + /// + /// + /// + /// The object being monitored + /// A lambda expression in the form of (obj) => obj.PropertyName + /// + public static PropertyDependency WhenPropertyChanges(this TObject source, Expression> propertyExpression) + where TObject : INotifyPropertyChanged + { + return new PropertyDependency(source, propertyExpression); + } + } +} + diff --git a/PropertyDependencyDemo/PropertyDependencyDemo/Mvvm/ObservableObject.cs b/PropertyDependencyDemo/PropertyDependencyDemo/Mvvm/ObservableObject.cs new file mode 100644 index 0000000..77125e2 --- /dev/null +++ b/PropertyDependencyDemo/PropertyDependencyDemo/Mvvm/ObservableObject.cs @@ -0,0 +1,124 @@ +using System; +using System.ComponentModel; +using System.Collections.Generic; +using System.Threading.Tasks; +using System.Linq.Expressions; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Linq; + +namespace PropertyDependencyDemo.Mvvm +{ + public class ObservableObject : INotifyPropertyChanged + { + readonly Dictionary> _propertyDependencies = new Dictionary> (); + readonly Dictionary>> _propertyActions = new Dictionary>> (); + readonly Dictionary>> _propertyTasks = new Dictionary>> (); + + public ObservableObject () + { + _propertyDependencies = new Dictionary> (); + _propertyActions = new Dictionary>> (); + _propertyTasks = new Dictionary>> (); + } + + public event PropertyChangedEventHandler PropertyChanged = delegate {}; + + /// + /// Allows for chaining multiple dependant property update notifications. + /// + /// + /// + /// + protected PropertyDependency WhenPropertyChanges(Expression> propertyExpression) + { + var propertyName = propertyExpression.ExtractPropertyName(); + return new PropertyDependency(this, propertyName, _propertyDependencies, _propertyActions, _propertyTasks); + } + + protected virtual void AfterPropertyChange(string propertyName) + { + } + + /// + /// This is used to set a specific value for a property. + /// + /// Type to set + /// Storage field + /// New value + /// Property expression + /// True if the property value was changed and an INotifyPropertyChanged was raised. + protected bool SetPropertyValue(ref T storageField, T newValue, Expression> propExpr) + { + if (Equals(storageField, newValue)) + return false; + storageField = newValue; + var prop = (PropertyInfo)((MemberExpression)propExpr.Body).Member; + RaisePropertyChanged(prop.Name); + return true; + } + + /// + /// This is used to set a specific value for a property. + /// + /// Type to set + /// Storage field + /// New value + /// Property Name + /// True if the property value was changed and an INotifyPropertyChanged was raised. + protected bool SetPropertyValue(ref T storageField, T newValue, [CallerMemberName] string propertyName = "") + { + if (Equals(storageField, newValue)) + return false; + storageField = newValue; + RaisePropertyChanged(propertyName); + return true; + } + + /// + /// Raises this object's PropertyChanged event. + /// + /// The property that has a new value. + public void RaisePropertyChanged([CallerMemberName]string propertyName = null) + { + PropertyChangedCore(propertyName); + + if (_propertyActions.ContainsKey(propertyName)) + _propertyActions[propertyName].ForEach(action => action(this, propertyName)); + + if (_propertyTasks.ContainsKey(propertyName)) + _propertyTasks[propertyName].ForEach(task => task().ConfigureAwait(true)); + + if (!_propertyDependencies.ContainsKey(propertyName)) + return; + + var depList = new List(); + var tmp = new Queue(_propertyDependencies[propertyName]); + while (tmp.Any()) + { + var dep = tmp.Dequeue(); + if (!depList.Contains(dep)) + depList.Add(dep); + if (_propertyDependencies.ContainsKey(dep)) + _propertyDependencies[dep].ForEach(tmp.Enqueue); + } + + depList.ForEach(PropertyChangedCore); + } + + void PropertyChangedCore(string propertyName) + { + var handler = PropertyChanged; + if (handler != null) + handler(this, new PropertyChangedEventArgs(propertyName)); + AfterPropertyChange(propertyName); + } + + protected void RaisePropertyChanged(Expression> propertyExpression) + { + var propertyName = propertyExpression.ExtractPropertyName(); + RaisePropertyChanged(propertyName); + } + } +} + diff --git a/PropertyDependencyDemo/PropertyDependencyDemo/Mvvm/PropertyDependency.cs b/PropertyDependencyDemo/PropertyDependencyDemo/Mvvm/PropertyDependency.cs new file mode 100644 index 0000000..9b63cd7 --- /dev/null +++ b/PropertyDependencyDemo/PropertyDependencyDemo/Mvvm/PropertyDependency.cs @@ -0,0 +1,119 @@ +using System; +using System.ComponentModel; +using System.Collections.Generic; +using System.Threading.Tasks; +using System.Linq.Expressions; + +namespace PropertyDependencyDemo.Mvvm +{ + /// + /// Simple strong-typed property notification subscription mechanism. + /// + /// + /// + public sealed class PropertyDependency + where TObject : INotifyPropertyChanged + { + readonly List _actions; + readonly List> _tasks; + readonly string _propertyName; + + public PropertyDependency(TObject source, string propertyName) + { + _actions = new List(); + _tasks = new List>(); + _propertyName = propertyName; + source.PropertyChanged += SourcePropertyChanged; + } + + void SourcePropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName != _propertyName) + return; + _actions.ForEach(action => action()); + _tasks.ForEach(task => task().ConfigureAwait(true)); + } + + public PropertyDependency(TObject source, Expression> propertyExpression) + : this(source, propertyExpression.ExtractPropertyName()) + { + } + + public PropertyDependency AlsoInvokeAction(Action action) + { + _actions.Add(action); + return this; + } + + public PropertyDependency AlsoInitiateTask(Func task) + { + _tasks.Add(task); + return this; + } + } + + /// + /// Tracks dependencies between properties of a bindable object. + /// + public sealed class PropertyDependency + { + readonly string _propertyName; + readonly ObservableObject _observable; + readonly Dictionary> _propertyDependencies; + readonly Dictionary>> _propertyActions; + readonly Dictionary>> _propertyTasks; + + internal PropertyDependency(ObservableObject observable, string propertyName, + Dictionary> propertyDependencies, + Dictionary>> propertyActions, + Dictionary>> propertyTasks) + { + _observable = observable; + _propertyName = propertyName; + _propertyDependencies = propertyDependencies; + _propertyActions = propertyActions; + _propertyTasks = propertyTasks; + } + + public PropertyDependency AlsoRaisePropertyChangedFor(Expression> propertyExpression) + { + var dependant = propertyExpression.ExtractPropertyName(); + return AlsoRaisePropertyChangedFor(dependant); + } + + public PropertyDependency AlsoRaisePropertyChangedFor(string propertyName) + { + if (!_observable.HasProperty(propertyName)) + throw new ArgumentException( + String.Format("Property '{0}' not found on type '{1}'.", propertyName, + _observable.GetType().Name), propertyName); + if (!_propertyDependencies.ContainsKey(_propertyName)) + _propertyDependencies.Add(_propertyName, new List()); + if (!_propertyDependencies[_propertyName].Contains(propertyName)) + _propertyDependencies[_propertyName].Add(propertyName); + return this; + } + + public PropertyDependency AlsoInvokeAction(Action action) + { + if (!_propertyActions.ContainsKey(_propertyName)) + _propertyActions.Add(_propertyName, new List>()); + _propertyActions[_propertyName].Add(action); + return this; + } + + public PropertyDependency AlsoInvokeAction(Action action) + { + return AlsoInvokeAction((a, b) => action()); + } + + public PropertyDependency AlsoInitiateTask(Func task) + { + if (!_propertyTasks.ContainsKey(_propertyName)) + _propertyTasks.Add(_propertyName, new List>()); + _propertyTasks[_propertyName].Add(task); + return this; + } + } +} + diff --git a/PropertyDependencyDemo/PropertyDependencyDemo/Mvvm/ReflectionExtensions.cs b/PropertyDependencyDemo/PropertyDependencyDemo/Mvvm/ReflectionExtensions.cs new file mode 100644 index 0000000..3a18926 --- /dev/null +++ b/PropertyDependencyDemo/PropertyDependencyDemo/Mvvm/ReflectionExtensions.cs @@ -0,0 +1,170 @@ +using System; +using System.Linq.Expressions; +using System.Reflection; + +namespace PropertyDependencyDemo.Mvvm +{ + public static class ReflectionExtensions + { + /// + /// Given a lambda expression that contains a single reference to a public property, retrieves the property's setter accessor. + /// + /// Data type of property + /// A lambda expression in the form of () => PropertyName + /// + public static Action ExtractPropertySetter(this Expression> propertyExpression) + { + if (propertyExpression == null) + throw new ArgumentNullException("propertyExpression"); + + var memberExpression = propertyExpression.Body as MemberExpression; + if (memberExpression == null) + throw new ArgumentException("The expression is not a member access expression.", "propertyExpression"); + + var property = memberExpression.Member as PropertyInfo; + if (property == null) + throw new ArgumentException("The member access expression does not access a property.", "propertyExpression"); + + var setMethod = property.SetMethod; + + if (setMethod == null) + throw new ArgumentException("The referenced property does not have a set method.", "propertyExpression"); + + if (setMethod.IsStatic) + throw new ArgumentException("The referenced property is a static property.", "propertyExpression"); + + Action action = (obj, val) => setMethod.Invoke(obj, new object[] { val }); + return action; + } + + /// + /// Extracts the property name from the property expression. + /// + /// Implementation borrowed from Jounce MVVM framework. + /// + /// The type of the property + /// A lambda expression in the form of () => PropertyName + /// When 'true' causes this method to return null results instead of throwing + /// an exception whenever a problem occurs while probing the type information. + /// The property name + public static string ExtractPropertyName(this Expression> propertyExpression, bool failSilently = false) + { + if (propertyExpression == null) + { + if (failSilently) + return null; + throw new ArgumentNullException("propertyExpression"); + } + + var memberExpression = propertyExpression.Body as MemberExpression; + if (memberExpression == null) + { + if (failSilently) + return null; + throw new ArgumentException("The expression is not a member access expression.", "propertyExpression"); + } + + var property = memberExpression.Member as PropertyInfo; + if (property == null) + { + if (failSilently) + return null; + throw new ArgumentException("The member access expression does not access a property.", "propertyExpression"); + } + + var getMethod = property.GetMethod; + + if (getMethod == null) + { + // this shouldn't happen - the expression would reject the property before reaching this far + if (failSilently) + return null; + throw new ArgumentException("The referenced property does not have a get method.", "propertyExpression"); + } + + if (getMethod.IsStatic) + { + if (failSilently) + return null; + throw new ArgumentException("The referenced property is a static property.", "propertyExpression"); + } + + return memberExpression.Member.Name; + } + + /// + /// Extracts the property name from the property expression. + /// + /// Implementation borrowed from Jounce MVVM framework. + /// + /// The type of the property + /// A lambda expression in the form of () => PropertyName + /// When 'true' causes this method to return null results instead of throwing + /// an exception whenever a problem occurs while probing the type information. + /// The property name + public static string ExtractPropertyName(this Expression> propertyExpression, bool failSilently = false) + { + if (propertyExpression == null) + { + if (failSilently) + return null; + throw new ArgumentNullException("propertyExpression"); + } + + var memberExpression = propertyExpression.Body as MemberExpression; + if (memberExpression == null) + { + if (failSilently) + return null; + throw new ArgumentException("The expression is not a member access expression.", "propertyExpression"); + } + + var property = memberExpression.Member as PropertyInfo; + if (property == null) + { + if (failSilently) + return null; + throw new ArgumentException("The member access expression does not access a property.", "propertyExpression"); + } + + var getMethod = property.GetMethod; + + if (getMethod == null) + { + // this shouldn't happen - the expression would reject the property before reaching this far + if (failSilently) + return null; + throw new ArgumentException("The referenced property does not have a get method.", "propertyExpression"); + } + + if (getMethod.IsStatic) + { + if (failSilently) + return null; + throw new ArgumentException("The referenced property is a static property.", "propertyExpression"); + } + + return memberExpression.Member.Name; + } + + /// + /// Inspects a type to see if it defines a property with the specified name and type. + /// + /// The type of the property + /// An instance of an object being inspected, or a variable of the corresponding class type (can be null). + /// The property name + /// Returns 'true' if the property is found. + public static bool HasProperty(this T obj, string propertyName) + { + if (String.IsNullOrEmpty(propertyName)) + return false; + + var type = Equals(obj, default(T)) ? typeof(T) : obj.GetType(); + + // Verify that the property name matches a realinstance property on this object. + return type.GetRuntimeProperty(propertyName) != null; + } + } + +} + diff --git a/PropertyDependencyDemo/PropertyDependencyDemo/MyPage.xaml b/PropertyDependencyDemo/PropertyDependencyDemo/MyPage.xaml new file mode 100644 index 0000000..b65d3ed --- /dev/null +++ b/PropertyDependencyDemo/PropertyDependencyDemo/MyPage.xaml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/PropertyDependencyDemo/PropertyDependencyDemo/MyPage.xaml.cs b/PropertyDependencyDemo/PropertyDependencyDemo/MyPage.xaml.cs new file mode 100644 index 0000000..fbed91a --- /dev/null +++ b/PropertyDependencyDemo/PropertyDependencyDemo/MyPage.xaml.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; + +using Xamarin.Forms; + +namespace PropertyDependencyDemo +{ + public partial class MyPage : ContentPage + { + public MyPage () + { + InitializeComponent (); + } + } +} + diff --git a/PropertyDependencyDemo/PropertyDependencyDemo/MyViewModel.cs b/PropertyDependencyDemo/PropertyDependencyDemo/MyViewModel.cs new file mode 100644 index 0000000..c3ffc5c --- /dev/null +++ b/PropertyDependencyDemo/PropertyDependencyDemo/MyViewModel.cs @@ -0,0 +1,60 @@ +using System; +using PropertyDependencyDemo.Mvvm; + +namespace PropertyDependencyDemo +{ + public class MyViewModel : ObservableObject + { + string _firstName; + string _lastName; + bool _showLastNameFirst; + + public string FirstName { + get { return _firstName; } + set { SetPropertyValue (ref _firstName, value); } + } + + public string LastName { + get { return _lastName; } + set { SetPropertyValue (ref _lastName, value); } + } + + public string FullName { + get { return ShowLastNameFirst ? String.Format ("{0}, {1}", _lastName, _firstName) : String.Format ("{0} {1}", _firstName, _lastName); } + } + + public bool ShowLastNameFirst { + get { return _showLastNameFirst; } + set { SetPropertyValue (ref _showLastNameFirst, value); } + } + + public string Initials { + get { return (String.IsNullOrEmpty (FirstName) ? "" : FirstName.Substring (0, 1)) + (String.IsNullOrEmpty (LastName) ? "" : LastName.Substring (0, 1)); } + } + + public DelegateCommand SaveCommand { get; private set; } + + public MyViewModel () + { + FirstName = "Keith"; + LastName = "Rome"; + + SaveCommand = new DelegateCommand (() => { + // TODO: Save Data ... + }, + () => !(String.IsNullOrEmpty (FirstName) || String.IsNullOrEmpty (LastName))); + + WhenPropertyChanges (() => FirstName) + .AlsoRaisePropertyChangedFor (() => FullName) + .AlsoRaisePropertyChangedFor (() => Initials) + .AlsoInvokeAction (SaveCommand.ChangeCanExecute); + WhenPropertyChanges (() => LastName) + .AlsoRaisePropertyChangedFor (() => FullName) + .AlsoRaisePropertyChangedFor (() => Initials) + .AlsoInvokeAction (SaveCommand.ChangeCanExecute); + WhenPropertyChanges (() => ShowLastNameFirst) + .AlsoRaisePropertyChangedFor (() => FullName); + } + } +} + diff --git a/PropertyDependencyDemo/PropertyDependencyDemo/Properties/AssemblyInfo.cs b/PropertyDependencyDemo/PropertyDependencyDemo/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..f377acf --- /dev/null +++ b/PropertyDependencyDemo/PropertyDependencyDemo/Properties/AssemblyInfo.cs @@ -0,0 +1,27 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle ("PropertyDependencyDemo")] +[assembly: AssemblyDescription ("")] +[assembly: AssemblyConfiguration ("")] +[assembly: AssemblyCompany ("Wintellect, LLC")] +[assembly: AssemblyProduct ("")] +[assembly: AssemblyCopyright ("2015 Wintellect, LLC")] +[assembly: AssemblyTrademark ("")] +[assembly: AssemblyCulture ("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion ("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/PropertyDependencyDemo/PropertyDependencyDemo/PropertyDependencyDemo.cs b/PropertyDependencyDemo/PropertyDependencyDemo/PropertyDependencyDemo.cs new file mode 100644 index 0000000..7275e9e --- /dev/null +++ b/PropertyDependencyDemo/PropertyDependencyDemo/PropertyDependencyDemo.cs @@ -0,0 +1,32 @@ +using Xamarin.Forms; + +namespace PropertyDependencyDemo +{ + public class App : Application + { + public App () + { + var viewModel = new MyViewModel (); + var view = new MyPage (); + view.BindingContext = viewModel; + + MainPage = new NavigationPage(view); + } + + protected override void OnStart () + { + // Handle when your app starts + } + + protected override void OnSleep () + { + // Handle when your app sleeps + } + + protected override void OnResume () + { + // Handle when your app resumes + } + } +} + diff --git a/PropertyDependencyDemo/PropertyDependencyDemo/PropertyDependencyDemo.csproj b/PropertyDependencyDemo/PropertyDependencyDemo/PropertyDependencyDemo.csproj new file mode 100644 index 0000000..ad9e121 --- /dev/null +++ b/PropertyDependencyDemo/PropertyDependencyDemo/PropertyDependencyDemo.csproj @@ -0,0 +1,70 @@ + + + + Debug + AnyCPU + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + {62CB0D3F-DD9D-4CEC-A286-6BDC4B31B726} + Library + PropertyDependencyDemo + PropertyDependencyDemo + v4.5 + Profile78 + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + false + + + full + true + bin\Release + prompt + 4 + false + + + + + + + + + + + + + MyPage.xaml + + + + + + + ..\packages\Xamarin.Forms.1.5.0.6447\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.Core.dll + + + ..\packages\Xamarin.Forms.1.5.0.6447\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.Xaml.dll + + + ..\packages\Xamarin.Forms.1.5.0.6447\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.Platform.dll + + + + + + + + + + + MSBuild:UpdateDesignTimeXaml + + + \ No newline at end of file diff --git a/PropertyDependencyDemo/PropertyDependencyDemo/packages.config b/PropertyDependencyDemo/PropertyDependencyDemo/packages.config new file mode 100644 index 0000000..4072e9f --- /dev/null +++ b/PropertyDependencyDemo/PropertyDependencyDemo/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/PropertyDependencyDemo/UITests/AppInitializer.cs b/PropertyDependencyDemo/UITests/AppInitializer.cs new file mode 100644 index 0000000..b975220 --- /dev/null +++ b/PropertyDependencyDemo/UITests/AppInitializer.cs @@ -0,0 +1,21 @@ +using System; +using System.IO; +using System.Linq; +using Xamarin.UITest; +using Xamarin.UITest.Queries; + +namespace PropertyDependencyDemo.UITests +{ + public class AppInitializer + { + public static IApp StartApp (Platform platform) + { + if (platform == Platform.Android) { + return ConfigureApp.Android.StartApp (); + } + + return ConfigureApp.iOS.StartApp (); + } + } +} + diff --git a/PropertyDependencyDemo/UITests/PropertyDependencyDemo.UITests.csproj b/PropertyDependencyDemo/UITests/PropertyDependencyDemo.UITests.csproj new file mode 100644 index 0000000..e8ca1bb --- /dev/null +++ b/PropertyDependencyDemo/UITests/PropertyDependencyDemo.UITests.csproj @@ -0,0 +1,61 @@ + + + + Debug + AnyCPU + {9672DE6E-A5F8-41FF-8250-E341ABFAEBFB} + Library + PropertyDependencyDemo.UITests + PropertyDependencyDemo.UITests + v4.5 + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + false + + + full + true + bin\Release + prompt + 4 + false + + + + + ..\packages\Xamarin.UITest.1.1.1\lib\Xamarin.UITest.dll + + + ..\packages\NUnit.2.6.4\lib\nunit.framework.dll + + + + + {5CB65EC5-5533-4E4A-B31C-F4320A648341} + PropertyDependencyDemo.iOS + False + False + + + {932823BE-C1C5-475D-A752-15EBDBAC6A63} + PropertyDependencyDemo.Droid + False + False + + + + + + + + + + + \ No newline at end of file diff --git a/PropertyDependencyDemo/UITests/Tests.cs b/PropertyDependencyDemo/UITests/Tests.cs new file mode 100644 index 0000000..9adc2db --- /dev/null +++ b/PropertyDependencyDemo/UITests/Tests.cs @@ -0,0 +1,38 @@ +using System; +using System.IO; +using System.Linq; +using NUnit.Framework; +using Xamarin.UITest; +using Xamarin.UITest.Queries; + +namespace PropertyDependencyDemo.UITests +{ + [TestFixture (Platform.Android)] + [TestFixture (Platform.iOS)] + public class Tests + { + IApp app; + Platform platform; + + public Tests (Platform platform) + { + this.platform = platform; + } + + [SetUp] + public void BeforeEachTest () + { + app = AppInitializer.StartApp (platform); + } + + [Test] + public void WelcomeTextIsDisplayed () + { + AppResult[] results = app.WaitForElement (c => c.Marked ("Welcome to Xamarin Forms!")); + app.Screenshot ("Welcome screen."); + + Assert.IsTrue (results.Any ()); + } + } +} + diff --git a/PropertyDependencyDemo/UITests/packages.config b/PropertyDependencyDemo/UITests/packages.config new file mode 100644 index 0000000..2d9e3ac --- /dev/null +++ b/PropertyDependencyDemo/UITests/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/PropertyDependencyDemo/iOS/AppDelegate.cs b/PropertyDependencyDemo/iOS/AppDelegate.cs new file mode 100644 index 0000000..8dc21a6 --- /dev/null +++ b/PropertyDependencyDemo/iOS/AppDelegate.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using Foundation; +using UIKit; + +namespace PropertyDependencyDemo.iOS +{ + [Register ("AppDelegate")] + public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate + { + public override bool FinishedLaunching (UIApplication app, NSDictionary options) + { + global::Xamarin.Forms.Forms.Init (); + + // Code for starting up the Xamarin Test Cloud Agent + #if ENABLE_TEST_CLOUD + Xamarin.Calabash.Start(); + #endif + + LoadApplication (new App ()); + + return base.FinishedLaunching (app, options); + } + } +} + diff --git a/PropertyDependencyDemo/iOS/Entitlements.plist b/PropertyDependencyDemo/iOS/Entitlements.plist new file mode 100644 index 0000000..e9a3005 --- /dev/null +++ b/PropertyDependencyDemo/iOS/Entitlements.plist @@ -0,0 +1,7 @@ + + + + + + + diff --git a/PropertyDependencyDemo/iOS/ITunesArtwork b/PropertyDependencyDemo/iOS/ITunesArtwork new file mode 100644 index 0000000..d0136ea Binary files /dev/null and b/PropertyDependencyDemo/iOS/ITunesArtwork differ diff --git a/PropertyDependencyDemo/iOS/ITunesArtwork@2x b/PropertyDependencyDemo/iOS/ITunesArtwork@2x new file mode 100644 index 0000000..fa2ebf7 Binary files /dev/null and b/PropertyDependencyDemo/iOS/ITunesArtwork@2x differ diff --git a/PropertyDependencyDemo/iOS/Info.plist b/PropertyDependencyDemo/iOS/Info.plist new file mode 100644 index 0000000..5d6c4af --- /dev/null +++ b/PropertyDependencyDemo/iOS/Info.plist @@ -0,0 +1,64 @@ + + + + + CFBundleDisplayName + PropertyDependencyDemo + CFBundleIdentifier + com.wintellect.propertydependencydemo + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + MinimumOSVersion + 7.0 + UIDeviceFamily + + 1 + 2 + + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + CFBundleIconFiles + + Icon-60@2x + Icon-60@3x + Icon-76 + Icon-76@2x + Default + Default@2x + Default-568h + Default-568h@2x + Default-Landscape + Default-Landscape@2x + Default-Portrait + Default-Portrait@2x + Icon-Small-40 + Icon-Small-40@2x + Icon-Small-40@3x + Icon-Small + Icon-Small@2x + Icon-Small@3x + + UILaunchStoryboardName + LaunchScreen + + + diff --git a/PropertyDependencyDemo/iOS/Main.cs b/PropertyDependencyDemo/iOS/Main.cs new file mode 100644 index 0000000..9cb32a1 --- /dev/null +++ b/PropertyDependencyDemo/iOS/Main.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using Foundation; +using UIKit; + +namespace PropertyDependencyDemo.iOS +{ + public class Application + { + // This is the main entry point of the application. + static void Main (string[] args) + { + // if you want to use a different Application Delegate class from "AppDelegate" + // you can specify it here. + UIApplication.Main (args, null, "AppDelegate"); + } + } +} + diff --git a/PropertyDependencyDemo/iOS/PropertyDependencyDemo.iOS.csproj b/PropertyDependencyDemo/iOS/PropertyDependencyDemo.iOS.csproj new file mode 100644 index 0000000..aabc0f5 --- /dev/null +++ b/PropertyDependencyDemo/iOS/PropertyDependencyDemo.iOS.csproj @@ -0,0 +1,125 @@ + + + + Debug + iPhoneSimulator + {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + {5CB65EC5-5533-4E4A-B31C-F4320A648341} + Exe + PropertyDependencyDemo.iOS + Resources + PropertyDependencyDemo.iOS + + + true + full + false + bin\iPhoneSimulator\Debug + DEBUG;ENABLE_TEST_CLOUD; + prompt + 4 + false + i386 + None + true + true + + + full + true + bin\iPhone\Release + prompt + 4 + Entitlements.plist + ARMv7, ARM64 + false + iPhone Developer + + + full + true + bin\iPhoneSimulator\Release + prompt + 4 + i386 + false + None + + + true + full + false + bin\iPhone\Debug + DEBUG;ENABLE_TEST_CLOUD; + prompt + 4 + false + ARMv7, ARM64 + Entitlements.plist + true + iPhone Developer + true + + + + + + + + ..\packages\Xamarin.TestCloud.Agent.0.16.2\lib\Xamarin.iOS10\Calabash.dll + + + ..\packages\Xamarin.Forms.1.5.0.6447\lib\Xamarin.iOS10\Xamarin.Forms.Platform.iOS.dll + + + ..\packages\Xamarin.Forms.1.5.0.6447\lib\Xamarin.iOS10\Xamarin.Forms.Core.dll + + + ..\packages\Xamarin.Forms.1.5.0.6447\lib\Xamarin.iOS10\Xamarin.Forms.Xaml.dll + + + ..\packages\Xamarin.Forms.1.5.0.6447\lib\Xamarin.iOS10\Xamarin.Forms.Platform.dll + + + + + {62CB0D3F-DD9D-4CEC-A286-6BDC4B31B726} + PropertyDependencyDemo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/PropertyDependencyDemo/iOS/Resources/Default-568h@2x.png b/PropertyDependencyDemo/iOS/Resources/Default-568h@2x.png new file mode 100644 index 0000000..26c6461 Binary files /dev/null and b/PropertyDependencyDemo/iOS/Resources/Default-568h@2x.png differ diff --git a/PropertyDependencyDemo/iOS/Resources/Default-Portrait.png b/PropertyDependencyDemo/iOS/Resources/Default-Portrait.png new file mode 100644 index 0000000..5d0d1ab Binary files /dev/null and b/PropertyDependencyDemo/iOS/Resources/Default-Portrait.png differ diff --git a/PropertyDependencyDemo/iOS/Resources/Default-Portrait@2x.png b/PropertyDependencyDemo/iOS/Resources/Default-Portrait@2x.png new file mode 100644 index 0000000..0ee2688 Binary files /dev/null and b/PropertyDependencyDemo/iOS/Resources/Default-Portrait@2x.png differ diff --git a/PropertyDependencyDemo/iOS/Resources/Default.png b/PropertyDependencyDemo/iOS/Resources/Default.png new file mode 100644 index 0000000..b74643c Binary files /dev/null and b/PropertyDependencyDemo/iOS/Resources/Default.png differ diff --git a/PropertyDependencyDemo/iOS/Resources/Default@2x.png b/PropertyDependencyDemo/iOS/Resources/Default@2x.png new file mode 100644 index 0000000..dbd6bd3 Binary files /dev/null and b/PropertyDependencyDemo/iOS/Resources/Default@2x.png differ diff --git a/PropertyDependencyDemo/iOS/Resources/Icon-60@2x.png b/PropertyDependencyDemo/iOS/Resources/Icon-60@2x.png new file mode 100644 index 0000000..4b03c42 Binary files /dev/null and b/PropertyDependencyDemo/iOS/Resources/Icon-60@2x.png differ diff --git a/PropertyDependencyDemo/iOS/Resources/Icon-60@3x.png b/PropertyDependencyDemo/iOS/Resources/Icon-60@3x.png new file mode 100644 index 0000000..b03ca1b Binary files /dev/null and b/PropertyDependencyDemo/iOS/Resources/Icon-60@3x.png differ diff --git a/PropertyDependencyDemo/iOS/Resources/Icon-76.png b/PropertyDependencyDemo/iOS/Resources/Icon-76.png new file mode 100644 index 0000000..587982e Binary files /dev/null and b/PropertyDependencyDemo/iOS/Resources/Icon-76.png differ diff --git a/PropertyDependencyDemo/iOS/Resources/Icon-76@2x.png b/PropertyDependencyDemo/iOS/Resources/Icon-76@2x.png new file mode 100644 index 0000000..cd4e2c8 Binary files /dev/null and b/PropertyDependencyDemo/iOS/Resources/Icon-76@2x.png differ diff --git a/PropertyDependencyDemo/iOS/Resources/Icon-Small-40.png b/PropertyDependencyDemo/iOS/Resources/Icon-Small-40.png new file mode 100644 index 0000000..6acff94 Binary files /dev/null and b/PropertyDependencyDemo/iOS/Resources/Icon-Small-40.png differ diff --git a/PropertyDependencyDemo/iOS/Resources/Icon-Small-40@2x.png b/PropertyDependencyDemo/iOS/Resources/Icon-Small-40@2x.png new file mode 100644 index 0000000..b833aac Binary files /dev/null and b/PropertyDependencyDemo/iOS/Resources/Icon-Small-40@2x.png differ diff --git a/PropertyDependencyDemo/iOS/Resources/Icon-Small-40@3x.png b/PropertyDependencyDemo/iOS/Resources/Icon-Small-40@3x.png new file mode 100644 index 0000000..ab8654e Binary files /dev/null and b/PropertyDependencyDemo/iOS/Resources/Icon-Small-40@3x.png differ diff --git a/PropertyDependencyDemo/iOS/Resources/Icon-Small.png b/PropertyDependencyDemo/iOS/Resources/Icon-Small.png new file mode 100644 index 0000000..33db7e7 Binary files /dev/null and b/PropertyDependencyDemo/iOS/Resources/Icon-Small.png differ diff --git a/PropertyDependencyDemo/iOS/Resources/Icon-Small@2x.png b/PropertyDependencyDemo/iOS/Resources/Icon-Small@2x.png new file mode 100644 index 0000000..bf45e25 Binary files /dev/null and b/PropertyDependencyDemo/iOS/Resources/Icon-Small@2x.png differ diff --git a/PropertyDependencyDemo/iOS/Resources/Icon-Small@3x.png b/PropertyDependencyDemo/iOS/Resources/Icon-Small@3x.png new file mode 100644 index 0000000..7ad3891 Binary files /dev/null and b/PropertyDependencyDemo/iOS/Resources/Icon-Small@3x.png differ diff --git a/PropertyDependencyDemo/iOS/Resources/LaunchScreen.storyboard b/PropertyDependencyDemo/iOS/Resources/LaunchScreen.storyboard new file mode 100644 index 0000000..a639c2f --- /dev/null +++ b/PropertyDependencyDemo/iOS/Resources/LaunchScreen.storyboard @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/PropertyDependencyDemo/iOS/packages.config b/PropertyDependencyDemo/iOS/packages.config new file mode 100644 index 0000000..37121cf --- /dev/null +++ b/PropertyDependencyDemo/iOS/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file