diff --git a/.gitignore b/.gitignore index f5786b4683..a599a267d4 100644 --- a/.gitignore +++ b/.gitignore @@ -156,3 +156,4 @@ $RECYCLE.BIN/ ## Monodevelop ################# *.userprefs +*.nugetreferenceswitcher diff --git a/Perspex.Controls/ItemsControl.cs b/Perspex.Controls/ItemsControl.cs index 4dab49dd98..18b60add05 100644 --- a/Perspex.Controls/ItemsControl.cs +++ b/Perspex.Controls/ItemsControl.cs @@ -8,6 +8,7 @@ namespace Perspex.Controls { using System; using System.Collections; + using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Diagnostics.CodeAnalysis; using System.Linq; @@ -35,7 +36,7 @@ namespace Perspex.Controls /// Defines the property. /// public static readonly PerspexProperty ItemsProperty = - PerspexProperty.Register("Items"); + PerspexProperty.Register("Items", defaultValue: new Collection()); /// /// Defines the property. diff --git a/Perspex.Xaml.Desktop/Perspex.Xaml.Desktop.csproj b/Perspex.Xaml.Desktop/Perspex.Xaml.Desktop.csproj new file mode 100644 index 0000000000..086fae3559 --- /dev/null +++ b/Perspex.Xaml.Desktop/Perspex.Xaml.Desktop.csproj @@ -0,0 +1,184 @@ + + + + + Debug + AnyCPU + {EB468C39-AAC4-4963-A7B2-0A405EA63EDD} + Library + Properties + Perspex.Xaml.Desktop + Perspex.Xaml.Desktop + v4.6 + 512 + + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Glass.1.4.2.0\lib\portable-net451+win81+wpa81\Glass.dll + True + + + ..\packages\OmniXaml.1.4.2.0\lib\portable-net451+win81+wpa81\OmniXaml.dll + True + + + ..\packages\OmniXaml.AppServices.1.4.2.0\lib\portable-net451+win81+wpa81\OmniXaml.AppServices.dll + True + + + ..\packages\OmniXaml.AppServices.Mvvm.1.4.2.0\lib\portable-net451+win81+wpa81\OmniXaml.AppServices.Mvvm.dll + True + + + ..\packages\OmniXaml.AppServices.NetCore.1.4.2.0\lib\net46\OmniXaml.AppServices.NetCore.dll + True + + + ..\packages\reactiveui-core.6.5.0\lib\Net45\ReactiveUI.dll + True + + + ..\packages\Serilog.1.5.6\lib\net45\Serilog.dll + True + + + ..\packages\Serilog.1.5.6\lib\net45\Serilog.FullNetFx.dll + True + + + False + $(SharpDXPackageBinDir)\SharpDX.dll + + + False + $(SharpDXPackageBinDir)\SharpDX.Direct2D1.dll + + + False + $(SharpDXPackageBinDir)\SharpDX.DXGI.dll + + + ..\packages\Splat.1.6.2\lib\Net45\Splat.dll + True + + + ..\packages\Sprache.SuperJMN.2.0.0.46\lib\portable-net451+win81+wpa81\Sprache.dll + True + + + + + + ..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll + True + + + ..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll + True + + + ..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll + True + + + ..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll + True + + + ..\packages\Rx-XAML.2.2.5\lib\net45\System.Reactive.Windows.Threading.dll + True + + + + + + + + + + + + + + + + + + + + + {d211e587-d8bc-45b9-95a4-f297c8fa5200} + Perspex.Animation + + + {b09b78d8-9b26-48b0-9149-d64a2f120f3f} + Perspex.Base + + + {d2221c82-4a25-4583-9b43-d791e3f6820c} + Perspex.Controls + + + {62024b2d-53eb-4638-b26b-85eeaa54866e} + Perspex.Input + + + {6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b} + Perspex.Interactivity + + + {42472427-4774-4c81-8aff-9f27b8e31721} + Perspex.Layout + + + {eb582467-6abb-43a1-b052-e981ba910e3a} + Perspex.SceneGraph + + + {f1baa01a-f176-4c6a-b39d-5b40bb1b148f} + Perspex.Styling + + + {3E53A01A-B331-47F3-B828-4A5717E77A24} + Perspex.Xaml + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/Perspex.Xaml.Desktop/Perspex.Xaml.Desktop.nugetreferenceswitcher b/Perspex.Xaml.Desktop/Perspex.Xaml.Desktop.nugetreferenceswitcher new file mode 100644 index 0000000000..e09f70cb8e --- /dev/null +++ b/Perspex.Xaml.Desktop/Perspex.Xaml.Desktop.nugetreferenceswitcher @@ -0,0 +1 @@ +OmniXaml.AppServices ../../OmniXAML/Source/OmniXaml.AppServices/OmniXaml.AppServices.csproj ../packages/OmniXaml.AppServices.1.4.0.0/lib/portable-net451+win81+wpa81/OmniXaml.AppServices.dll diff --git a/Perspex.Xaml.Desktop/PerspexInflatableTypeFactory.cs b/Perspex.Xaml.Desktop/PerspexInflatableTypeFactory.cs new file mode 100644 index 0000000000..384a6dc513 --- /dev/null +++ b/Perspex.Xaml.Desktop/PerspexInflatableTypeFactory.cs @@ -0,0 +1,17 @@ +namespace Perspex.Xaml.Desktop +{ + using System; + using System.Collections.ObjectModel; + using Controls; + using OmniXaml; + using OmniXaml.AppServices; + using OmniXaml.AppServices.NetCore; + + public class PerspexInflatableTypeFactory : InflatableTypeFactory + { + public PerspexInflatableTypeFactory() : base(new TypeFactory(), new InflatableTranslator(), typeFactory => new PerspexXamlLoader(typeFactory)) + { + Inflatables = new Collection { typeof(Window), typeof(UserControl) }; + } + } +} \ No newline at end of file diff --git a/Perspex.Xaml.Desktop/PerspexParserFactory.cs b/Perspex.Xaml.Desktop/PerspexParserFactory.cs new file mode 100644 index 0000000000..3253d53f85 --- /dev/null +++ b/Perspex.Xaml.Desktop/PerspexParserFactory.cs @@ -0,0 +1,55 @@ +namespace Perspex.Xaml.Desktop +{ + using Context; + using HighLevel; + using OmniXaml; + using OmniXaml.ObjectAssembler; + using OmniXaml.Parsers.ProtoParser; + using OmniXaml.Parsers.XamlNodes; + + public class PerspexParserFactory : IXamlParserFactory + { + private readonly IWiringContext wiringContext; + + public PerspexParserFactory(ITypeFactory typeFactory) + { + wiringContext = PerspexWiringContextFactory.GetContext(typeFactory); + } + + public IXamlParser CreateForReadingFree() + { + var objectAssemblerForUndefinedRoot = GetObjectAssemblerForUndefinedRoot(); + + return CreateParser(objectAssemblerForUndefinedRoot); + } + + private IXamlParser CreateParser(IObjectAssembler objectAssemblerForUndefinedRoot) + { + var xamlInstructionParser = new OrderAwareXamlInstructionParser(new XamlInstructionParser(wiringContext)); + + var phaseParserKit = new PhaseParserKit( + new XamlProtoInstructionParser(wiringContext), + xamlInstructionParser, + objectAssemblerForUndefinedRoot); + + return new XamlXmlParser(phaseParserKit); + } + + private IObjectAssembler GetObjectAssemblerForUndefinedRoot() + { + return new ObjectAssembler(wiringContext, new TopDownMemberValueContext()); + } + + public IXamlParser CreateForReadingSpecificInstance(object rootInstance) + { + var objectAssemblerForUndefinedRoot = GetObjectAssemblerForSpecificRoot(rootInstance); + + return CreateParser(objectAssemblerForUndefinedRoot); + } + + private IObjectAssembler GetObjectAssemblerForSpecificRoot(object rootInstance) + { + return new PerspexObjectAssembler(wiringContext, new ObjectAssemblerSettings { RootInstance = rootInstance }); + } + } +} \ No newline at end of file diff --git a/Perspex.Xaml.Desktop/PerspexWindow.cs b/Perspex.Xaml.Desktop/PerspexWindow.cs new file mode 100644 index 0000000000..23c727e5b5 --- /dev/null +++ b/Perspex.Xaml.Desktop/PerspexWindow.cs @@ -0,0 +1,13 @@ +namespace Perspex.Xaml.Desktop +{ + using Controls; + using OmniXaml.AppServices.Mvvm; + + public class PerspexWindow : Window, IView + { + public void SetViewModel(object viewModel) + { + this.DataContext = viewModel; + } + } +} \ No newline at end of file diff --git a/Perspex.Xaml.Desktop/PerspexXamlLoader.cs b/Perspex.Xaml.Desktop/PerspexXamlLoader.cs new file mode 100644 index 0000000000..2d2bb68f45 --- /dev/null +++ b/Perspex.Xaml.Desktop/PerspexXamlLoader.cs @@ -0,0 +1,11 @@ +namespace Perspex.Xaml.Desktop +{ + using OmniXaml; + + public class PerspexXamlLoader : XamlLoader + { + public PerspexXamlLoader(ITypeFactory typeFactory) : base(new PerspexParserFactory(typeFactory)) + { + } + } +} \ No newline at end of file diff --git a/Perspex.Xaml.Desktop/Properties/AssemblyInfo.cs b/Perspex.Xaml.Desktop/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..5b515a55be --- /dev/null +++ b/Perspex.Xaml.Desktop/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +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("Perspex.Xaml.Desktop")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Perspex.Xaml.Desktop")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[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("eb468c39-aac4-4963-a7b2-0a405ea63edd")] + +// 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 Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Perspex.Xaml.Desktop/WindowsResourceProvider.cs b/Perspex.Xaml.Desktop/WindowsResourceProvider.cs new file mode 100644 index 0000000000..a249b758e1 --- /dev/null +++ b/Perspex.Xaml.Desktop/WindowsResourceProvider.cs @@ -0,0 +1,17 @@ +namespace Perspex.Xaml.Desktop +{ + using System; + using System.IO; + using System.Reflection; + using HighLevel; + + public class WindowsResourceProvider : IResourceProvider + { + public Stream GetStream(Uri uri) + { + var absoluteUri = new Uri(Assembly.GetExecutingAssembly().Location, UriKind.Absolute); + var finalUri = new Uri(absoluteUri, uri); + return new FileStream(finalUri.LocalPath, FileMode.Open); + } + } +} \ No newline at end of file diff --git a/Perspex.Xaml.Desktop/packages.config b/Perspex.Xaml.Desktop/packages.config new file mode 100644 index 0000000000..d8633a7779 --- /dev/null +++ b/Perspex.Xaml.Desktop/packages.config @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Perspex.Xaml/Context/PerspexObjectAssembler.cs b/Perspex.Xaml/Context/PerspexObjectAssembler.cs new file mode 100644 index 0000000000..b147ad42ee --- /dev/null +++ b/Perspex.Xaml/Context/PerspexObjectAssembler.cs @@ -0,0 +1,35 @@ +namespace Perspex.Xaml.Context +{ + using System; + using OmniXaml; + using OmniXaml.ObjectAssembler; + using Templates; + + public class PerspexObjectAssembler : IObjectAssembler + { + private readonly TemplateHostingObjectAssembler objectAssembler; + + public PerspexObjectAssembler(IWiringContext wiringContext, ObjectAssemblerSettings objectAssemblerSettings = null) + { + var mapping = new DeferredLoaderMapping(); + mapping.Map(template => template.Content, new TemplateLoader()); + + var assembler = new ObjectAssembler(wiringContext, new TopDownMemberValueContext(), objectAssemblerSettings); + objectAssembler = new TemplateHostingObjectAssembler(assembler, mapping); + } + + + public object Result => objectAssembler.Result; + public EventHandler XamlSetValueHandler { get; set; } + public IWiringContext WiringContext => objectAssembler.WiringContext; + public void Process(XamlInstruction node) + { + objectAssembler.Process(node); + } + + public void OverrideInstance(object instance) + { + objectAssembler.OverrideInstance(instance); + } + } +} \ No newline at end of file diff --git a/Perspex.Xaml/Context/PerspexTypeRepository.cs b/Perspex.Xaml/Context/PerspexTypeRepository.cs new file mode 100644 index 0000000000..fa7dc74fc4 --- /dev/null +++ b/Perspex.Xaml/Context/PerspexTypeRepository.cs @@ -0,0 +1,29 @@ +namespace Perspex.Xaml.Context +{ + using System; + using DataBinding; + using Glass; + using OmniXaml; + using OmniXaml.Typing; + + public class PerspexTypeRepository : XamlTypeRepository + { + private readonly ITypeFactory typeFactory; + private readonly IPerspexPropertyBinder propertyBinder; + + public PerspexTypeRepository(IXamlNamespaceRegistry xamlNamespaceRegistry, + ITypeFactory typeFactory, + ITypeFeatureProvider featureProvider, + IPerspexPropertyBinder propertyBinder) : base(xamlNamespaceRegistry, typeFactory, featureProvider) + { + this.typeFactory = typeFactory; + this.propertyBinder = propertyBinder; + } + + public override XamlType GetXamlType(Type type) + { + Guard.ThrowIfNull(type, nameof(type)); + return new PerspexXamlType(type, this, typeFactory, FeatureProvider, propertyBinder); + } + } +} \ No newline at end of file diff --git a/Perspex.Xaml/Context/PerspexWiringContext.cs b/Perspex.Xaml/Context/PerspexWiringContext.cs new file mode 100644 index 0000000000..841b4b6167 --- /dev/null +++ b/Perspex.Xaml/Context/PerspexWiringContext.cs @@ -0,0 +1,110 @@ +namespace Perspex.Xaml.Context +{ + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Reflection; + using Controls; + using Converters; + using DataBinding; + using Glass; + using MarkupExtensions; + using Media; + using Media.Imaging; + using OmniXaml; + using OmniXaml.Builder; + using OmniXaml.TypeConversion; + using OmniXaml.Typing; + using Templates; + + public class PerspexWiringContext : IWiringContext + { + private readonly WiringContext context; + private const string PerspexNs = "https://github.com/grokys/Perspex"; + + public PerspexWiringContext(ITypeFactory typeFactory) + { + var featureProvider = new TypeFeatureProvider(GetContentPropertyProvider(), GetConverterProvider()); + + var xamlNamespaceRegistry = CreateXamlNamespaceRegistry(); + var perspexPropertyBinder = new PerspexPropertyBinder(featureProvider.ConverterProvider); + var xamlTypeRepository = new PerspexTypeRepository(xamlNamespaceRegistry, typeFactory, featureProvider, perspexPropertyBinder); + var typeContext = new TypeContext(xamlTypeRepository, xamlNamespaceRegistry, typeFactory); + context = new WiringContext(typeContext, featureProvider); + } + + private static XamlNamespaceRegistry CreateXamlNamespaceRegistry() + { + var xamlNamespaceRegistry = new XamlNamespaceRegistry(); + + var rootType = typeof(Control); + var bindingType = typeof(BindingExtension); + var templateType = typeof(XamlDataTemplate); + + var definitionForRoot = XamlNamespace + .Map(PerspexNs) + .With( + new[] + { + Route.Assembly(rootType.GetTypeInfo().Assembly).WithNamespaces( + new[] + { + rootType.Namespace + }), + Route.Assembly(bindingType.GetTypeInfo().Assembly).WithNamespaces( + new[] + { + bindingType.Namespace, + }), + Route.Assembly(templateType.GetTypeInfo().Assembly).WithNamespaces( + new[] + { + templateType.Namespace, + }) + }); + + foreach (var ns in new List { definitionForRoot }) + { + xamlNamespaceRegistry.AddNamespace(ns); + } + + xamlNamespaceRegistry.RegisterPrefix(new PrefixRegistration(string.Empty, PerspexNs)); + + return xamlNamespaceRegistry; + } + + private static ITypeConverterProvider GetConverterProvider() + { + var typeConverterProvider = new TypeConverterProvider(); + var converters = new[] + { + new TypeConverterRegistration(typeof (Bitmap), new BitmapConverter()), + new TypeConverterRegistration(typeof (GridLength), new GridLengthTypeConverter()), + new TypeConverterRegistration(typeof (Brush), new BrushConverter()), + new TypeConverterRegistration(typeof (Thickness), new ThicknessConverter()), + }; + + typeConverterProvider.AddAll(converters); + return typeConverterProvider; + } + + private static ContentPropertyProvider GetContentPropertyProvider() + { + var contentPropertyProvider = new ContentPropertyProvider(); + var contentProperties = new Collection + { + new ContentPropertyDefinition(typeof (ContentControl), "Content"), + new ContentPropertyDefinition(typeof (ItemsControl), "Items"), + new ContentPropertyDefinition(typeof (Panel), "Children"), + new ContentPropertyDefinition(typeof (XamlDataTemplate), "Content"), + new ContentPropertyDefinition(typeof (Decorator), "Child"), + }; + + contentPropertyProvider.AddAll(contentProperties); + + return contentPropertyProvider; + } + + public ITypeContext TypeContext => context.TypeContext; + public ITypeFeatureProvider FeatureProvider => context.FeatureProvider; + } +} \ No newline at end of file diff --git a/Perspex.Xaml/Context/PerspexXamlMember.cs b/Perspex.Xaml/Context/PerspexXamlMember.cs new file mode 100644 index 0000000000..58ad1c6c64 --- /dev/null +++ b/Perspex.Xaml/Context/PerspexXamlMember.cs @@ -0,0 +1,31 @@ +namespace Perspex.Xaml.Context +{ + using DataBinding; + using OmniXaml; + using OmniXaml.Typing; + + public class PerspexXamlMember : XamlMember + { + private readonly IPerspexPropertyBinder propertyBinder; + + public PerspexXamlMember(string name, + XamlType owner, + IXamlTypeRepository xamlTypeRepository, + ITypeFeatureProvider featureProvider, + IPerspexPropertyBinder propertyBinder) + : base(name, owner, xamlTypeRepository, featureProvider) + { + this.propertyBinder = propertyBinder; + } + + protected override IXamlMemberValuePlugin LookupXamlMemberValueConnector() + { + return new PerspexXamlMemberValuePlugin(this, propertyBinder); + } + + public override string ToString() + { + return "Perspex XAML Member " + base.ToString(); + } + } +} \ No newline at end of file diff --git a/Perspex.Xaml/Context/PerspexXamlMemberValuePlugin.cs b/Perspex.Xaml/Context/PerspexXamlMemberValuePlugin.cs new file mode 100644 index 0000000000..e52031e023 --- /dev/null +++ b/Perspex.Xaml/Context/PerspexXamlMemberValuePlugin.cs @@ -0,0 +1,100 @@ +namespace Perspex.Xaml.Context +{ + using System; + using System.Reactive.Linq; + using Controls; + using DataBinding; + using Glass; + using OmniXaml.Typing; + + public class PerspexXamlMemberValuePlugin : MemberValuePlugin + { + private readonly XamlMember xamlMember; + private readonly IPerspexPropertyBinder propertyBinder; + + public PerspexXamlMemberValuePlugin(XamlMember xamlMember, IPerspexPropertyBinder propertyBinder) : base(xamlMember) + { + this.xamlMember = xamlMember; + this.propertyBinder = propertyBinder; + } + + public override void SetValue(object instance, object value) + { + if (ValueRequiresSpecialHandling(value)) + { + HandleSpecialValue(instance, value); + } + else + { + base.SetValue(instance, value); + } + } + + private void HandleSpecialValue(object instance, object value) + { + var definition = value as XamlBindingDefinition; + if (definition != null) + { + HandleXamlBindingDefinition(definition); + } + else if (IsPerspexProperty) + { + HandlePerspexProperty(instance, value); + } + else + { + throw new InvalidOperationException($"Cannot handle the value {value} for member {this} and the instance {instance}"); + } + } + + private void HandlePerspexProperty(object instance, object value) + { + var pp = PerspexProperty; + var po = (PerspexObject) instance; + po.SetValue(pp, value); + } + + private void HandleXamlBindingDefinition(XamlBindingDefinition xamlBindingDefinition) + { + PerspexObject subjectObject = xamlBindingDefinition.Target; + propertyBinder.Create(xamlBindingDefinition); + + var observableForDataContext = subjectObject.GetObservable(Control.DataContextProperty); + observableForDataContext.Where(o => o != null).Subscribe(_ => BindToDataContextWhenItsSet(xamlBindingDefinition)); + } + + private void BindToDataContextWhenItsSet(XamlBindingDefinition definition) + { + var target = definition.Target; + var dataContext = target.DataContext; + + var binding = propertyBinder.GetBinding(target, definition.TargetProperty); + binding.Bind(dataContext); + } + + // ReSharper disable once MemberCanBePrivate.Global + public PerspexProperty PerspexProperty + { + get + { + var underlyingType = xamlMember.DeclaringType.UnderlyingType; + var name = xamlMember.Name + "Property"; + + var value = ReflectionExtensions.GetValueOfStaticField(underlyingType, name); + return value as PerspexProperty; + } + } + + private bool ValueRequiresSpecialHandling(object value) + { + return value is XamlBindingDefinition || IsPerspexProperty; + } + + private bool IsPerspexProperty => PerspexProperty != null; + + public override string ToString() + { + return $"{{Perspex Value Connector for member {xamlMember}}}"; + } + } +} \ No newline at end of file diff --git a/Perspex.Xaml/Context/PerspexXamlType.cs b/Perspex.Xaml/Context/PerspexXamlType.cs new file mode 100644 index 0000000000..bf377d03df --- /dev/null +++ b/Perspex.Xaml/Context/PerspexXamlType.cs @@ -0,0 +1,33 @@ +namespace Perspex.Xaml.Context +{ + using System; + using DataBinding; + using OmniXaml; + using OmniXaml.Typing; + + public class PerspexXamlType : XamlType + { + private readonly IPerspexPropertyBinder propertyBinder; + + public PerspexXamlType(Type type, + IXamlTypeRepository typeRepository, + ITypeFactory typeFactory, + ITypeFeatureProvider featureProvider, + IPerspexPropertyBinder propertyBinder) : base(type, typeRepository, typeFactory, featureProvider) + { + this.propertyBinder = propertyBinder; + } + + protected IPerspexPropertyBinder PropertyBinder => propertyBinder; + + protected override XamlMember LookupMember(string name) + { + return new PerspexXamlMember(name, this, TypeRepository, FeatureProvider, propertyBinder); + } + + public override string ToString() + { + return "Perspex XAML Type " + base.ToString(); + } + } +} \ No newline at end of file diff --git a/Perspex.Xaml/Converters/BitmapConverter.cs b/Perspex.Xaml/Converters/BitmapConverter.cs new file mode 100644 index 0000000000..3d758163d8 --- /dev/null +++ b/Perspex.Xaml/Converters/BitmapConverter.cs @@ -0,0 +1,31 @@ +namespace Perspex.Xaml.Converters +{ + using System; + using System.Globalization; + using Media.Imaging; + using OmniXaml.TypeConversion; + + public class BitmapConverter : ITypeConverter + { + public bool CanConvertFrom(IXamlTypeConverterContext context, Type sourceType) + { + return true; + } + + public bool CanConvertTo(IXamlTypeConverterContext context, Type destinationType) + { + return true; + } + + public object ConvertFrom(IXamlTypeConverterContext context, CultureInfo culture, object value) + { + var path = (string)value; + return new Bitmap(path); + } + + public object ConvertTo(IXamlTypeConverterContext context, CultureInfo culture, object value, Type destinationType) + { + return new Bitmap(10, 10); + } + } +} \ No newline at end of file diff --git a/Perspex.Xaml/Converters/BrushConverter.cs b/Perspex.Xaml/Converters/BrushConverter.cs new file mode 100644 index 0000000000..28e50ac615 --- /dev/null +++ b/Perspex.Xaml/Converters/BrushConverter.cs @@ -0,0 +1,83 @@ +namespace Perspex.Xaml.Converters +{ + using System; + using System.Globalization; + using System.Text; + using Media; + using Media.Imaging; + using OmniXaml.TypeConversion; + using Platform; + + public class BrushConverter : ITypeConverter + { + public bool CanConvertFrom(IXamlTypeConverterContext context, Type sourceType) + { + return true; + } + + public bool CanConvertTo(IXamlTypeConverterContext context, Type destinationType) + { + return true; + } + + public object ConvertFrom(IXamlTypeConverterContext context, CultureInfo culture, object value) + { + var colorString = (string)value; + + var color = DecodeColor(colorString); + + return new SolidColorBrush(color); + } + + private static Color DecodeColor(string colorString) + { + if (colorString[0] == '#') + { + var restOfValue = colorString.Remove(0, 1); + + if (restOfValue.Length == 8) + { + var a = Convert.ToByte(restOfValue.Substring(0, 2), 16); + var r = Convert.ToByte(restOfValue.Substring(2, 2), 16); + var g = Convert.ToByte(restOfValue.Substring(6, 2), 16); + var b = Convert.ToByte(restOfValue.Substring(8, 2), 16); + return Color.FromArgb(a, r, g, b); + } + if (restOfValue.Length == 6) + { + var r = Convert.ToByte(restOfValue.Substring(0, 2), 16); + var g = Convert.ToByte(restOfValue.Substring(2, 2), 16); + var b = Convert.ToByte(restOfValue.Substring(4, 2), 16); + return Color.FromRgb(r, g, b); + } + + throw new InvalidOperationException("The color code format cannot be parsed"); + } + else + { + return DecodeFromNamedColor(colorString); + } + + throw new InvalidOperationException($"The color cannot be decoded from the string \"{colorString}\""); + } + + private static Color DecodeFromNamedColor(string colorString) + { + if (colorString == "Crimson") + { + return DecodeColor("#DC143C"); + } + if (colorString == "Coral") + { + return DecodeColor("#FF7F50"); + } + + throw new NotImplementedException(); + } + + public object ConvertTo(IXamlTypeConverterContext context, CultureInfo culture, object value, Type destinationType) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/Perspex.Xaml/Converters/GridLengthTypeConverter.cs b/Perspex.Xaml/Converters/GridLengthTypeConverter.cs new file mode 100644 index 0000000000..0a013a92a4 --- /dev/null +++ b/Perspex.Xaml/Converters/GridLengthTypeConverter.cs @@ -0,0 +1,45 @@ +namespace Perspex.Xaml.Converters +{ + using System; + using System.Globalization; + using Controls; + using OmniXaml.TypeConversion; + + public class GridLengthTypeConverter : ITypeConverter + { + public object ConvertFrom(IXamlTypeConverterContext context, CultureInfo culture, object value) + { + var str = value as string; + + if (str != null) + { + if (string.Equals(str, "Auto")) + { + return new GridLength(0, GridUnitType.Auto); + } + } + + return new GridLength(1, GridUnitType.Star); + } + + public object ConvertTo(IXamlTypeConverterContext context, CultureInfo culture, object value, Type destinationType) + { + if ((string) value == "Auto") + { + return new GridLength(0, GridUnitType.Auto); + } + + return new GridLength(1, GridUnitType.Star); + } + + public bool CanConvertTo(IXamlTypeConverterContext context, Type destinationType) + { + return true; + } + + public bool CanConvertFrom(IXamlTypeConverterContext context, Type sourceType) + { + return true; + } + } +} \ No newline at end of file diff --git a/Perspex.Xaml/Converters/ThicknessConverter.cs b/Perspex.Xaml/Converters/ThicknessConverter.cs new file mode 100644 index 0000000000..54c98316f6 --- /dev/null +++ b/Perspex.Xaml/Converters/ThicknessConverter.cs @@ -0,0 +1,75 @@ +namespace Perspex.Xaml.Converters +{ + using System; + using System.Collections.Generic; + using System.Globalization; + using System.Linq; + using OmniXaml.TypeConversion; + + public class ThicknessConverter : ITypeConverter + { + public object ConvertFrom(IXamlTypeConverterContext context, CultureInfo culture, object value) + { + var s = value as string; + if (s != null) + { + return ConvertFromString(s); + } + + return null; + } + + private static Thickness ConvertFromString(string s) + { + var parts = s.Split(',') + .Take(4) + .Select(part => part.Trim()); + + if (parts.Count() == 1) + { + var uniformLength = double.Parse(parts.First()); + return new Thickness(uniformLength); + } + + double left = 0, top = 0, right = 0, bottom = 0; + + IList> setValue = new List> + { + val => left = val, + val => top = val, + val => right = val, + val => bottom = val, + }; + + var i = 0; + foreach (var part in parts) + { + var v = double.Parse(part); + setValue[i](v); + i++; + } + + return new Thickness(left, top, right, bottom); + } + + public object ConvertTo(IXamlTypeConverterContext context, CultureInfo culture, object value, Type destinationType) + { + throw new System.NotImplementedException(); + } + + public bool CanConvertTo(IXamlTypeConverterContext context, Type destinationType) + { + throw new NotImplementedException(); + } + + public bool CanConvertFrom(IXamlTypeConverterContext context, Type sourceType) + { + if (sourceType == typeof(string)) + { + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/Perspex.Xaml/DataBinding/ChangeTracking/ObservablePropertyBranch.cs b/Perspex.Xaml/DataBinding/ChangeTracking/ObservablePropertyBranch.cs new file mode 100644 index 0000000000..5a1ccb6faa --- /dev/null +++ b/Perspex.Xaml/DataBinding/ChangeTracking/ObservablePropertyBranch.cs @@ -0,0 +1,97 @@ +namespace Perspex.Xaml.DataBinding.ChangeTracking +{ + using System; + using System.Collections.Generic; + using System.ComponentModel; + using System.Linq; + using System.Reactive.Linq; + using System.Reflection; + using Glass; + + public class ObservablePropertyBranch + { + private readonly object root; + private readonly PropertyPath propertyPath; + private PropertyMountPoint mountPoint; + + public ObservablePropertyBranch(object root, PropertyPath propertyPath) + { + Guard.ThrowIfNull(root, nameof(root)); + Guard.ThrowIfNull(propertyPath, nameof(propertyPath)); + + this.root = root; + this.propertyPath = propertyPath; + mountPoint = new PropertyMountPoint(root, propertyPath); + var subscriptions = GetInpcNodes(); + Changed = CreateObservableFromNodes(subscriptions); + } + + private IObservable CreateObservableFromNodes(IEnumerable subscriptions) + { + return subscriptions.Select( + subscription => Observable.FromEventPattern( + ev => subscription.Parent.PropertyChanged += ev, + handler => subscription.Parent.PropertyChanged -= handler) + .Do(_ => mountPoint = new PropertyMountPoint(root, propertyPath)) + .Where(pattern => pattern.EventArgs.PropertyName == subscription.PropertyName)) + .Merge(); + } + + private IEnumerable GetInpcNodes() + { + return GetSubscriptionsRecursive(root, propertyPath, 0); + } + + private IEnumerable GetSubscriptionsRecursive(object current, PropertyPath propertyPath, int i) + { + var subscriptions = new List(); + var inpc = current as INotifyPropertyChanged; + + if (inpc == null) + { + return subscriptions; + } + + var nextPropertyName = propertyPath.Chunks[i]; + subscriptions.Add(new InpcNode(inpc, nextPropertyName)); + + if (i < this.propertyPath.Chunks.Length) + { + var currentObjectTypeInfo = current.GetType().GetTypeInfo(); + var nextProperty = currentObjectTypeInfo.GetDeclaredProperty(nextPropertyName); + var nextInstance = nextProperty.GetValue(current); + subscriptions.AddRange(GetSubscriptionsRecursive(nextInstance, propertyPath, i + 1)); + } + + return subscriptions; + } + + public IObservable Changed { get; } + + public object Value + { + get + { + return mountPoint.Value; + } + set + { + mountPoint.Value = value; + } + } + + public Type Type => mountPoint.ProperyType; + + private class InpcNode + { + public InpcNode(INotifyPropertyChanged parent, string propertyName) + { + Parent = parent; + PropertyName = propertyName; + } + + public INotifyPropertyChanged Parent { get; } + public string PropertyName { get; } + } + } +} \ No newline at end of file diff --git a/Perspex.Xaml/DataBinding/ChangeTracking/PropertyMountPoint.cs b/Perspex.Xaml/DataBinding/ChangeTracking/PropertyMountPoint.cs new file mode 100644 index 0000000000..40e73793f3 --- /dev/null +++ b/Perspex.Xaml/DataBinding/ChangeTracking/PropertyMountPoint.cs @@ -0,0 +1,48 @@ +namespace Perspex.Xaml.DataBinding.ChangeTracking +{ + using System; + using System.Reflection; + using Glass; + + public class PropertyMountPoint + { + private readonly TargettedProperty referencedTargettedProperty; + + public PropertyMountPoint(object origin, PropertyPath propertyPath) + { + Guard.ThrowIfNull(origin, nameof(origin)); + Guard.ThrowIfNull(propertyPath, nameof(propertyPath)); + + this.referencedTargettedProperty = GetReferencedPropertyInfo(origin, propertyPath, 0); + } + + private static TargettedProperty GetReferencedPropertyInfo(object current, PropertyPath propertyPath, int level) + { + var typeInfo = current.GetType().GetTypeInfo(); + var leftPropertyInfo = typeInfo.GetDeclaredProperty(propertyPath.Chunks[level]); + + if (level == propertyPath.Chunks.Length - 1) + { + return new TargettedProperty(current, leftPropertyInfo); + } + + var nextInstance = leftPropertyInfo.GetValue(current); + + return GetReferencedPropertyInfo(nextInstance, propertyPath, level + 1); + } + + public object Value + { + get + { + return referencedTargettedProperty.Value; + } + set + { + referencedTargettedProperty.Value = value; + } + } + + public Type ProperyType => referencedTargettedProperty.PropertyType; + } +} \ No newline at end of file diff --git a/Perspex.Xaml/DataBinding/ChangeTracking/PropertyPath.cs b/Perspex.Xaml/DataBinding/ChangeTracking/PropertyPath.cs new file mode 100644 index 0000000000..9485af8b5b --- /dev/null +++ b/Perspex.Xaml/DataBinding/ChangeTracking/PropertyPath.cs @@ -0,0 +1,28 @@ +namespace Perspex.Xaml.DataBinding.ChangeTracking +{ + public class PropertyPath + { + private string[] chunks; + + private PropertyPath(PropertyPath propertyPath) + { + this.chunks = propertyPath.Chunks; + } + + public PropertyPath(string path) + { + chunks = path.Split('.'); + } + + public string[] Chunks + { + get { return chunks; } + set { chunks = value; } + } + + public PropertyPath Clone() + { + return new PropertyPath(this); + } + } +} \ No newline at end of file diff --git a/Perspex.Xaml/DataBinding/ChangeTracking/TargettedProperty.cs b/Perspex.Xaml/DataBinding/ChangeTracking/TargettedProperty.cs new file mode 100644 index 0000000000..28913efc48 --- /dev/null +++ b/Perspex.Xaml/DataBinding/ChangeTracking/TargettedProperty.cs @@ -0,0 +1,34 @@ +namespace Perspex.Xaml.DataBinding.ChangeTracking +{ + using System; + using System.Reflection; + using Controls; + using Glass; + + class TargettedProperty + { + private readonly object instance; + private readonly PropertyInfo propertyInfo; + + public TargettedProperty(object instance, PropertyInfo propertyInfo) + { + Guard.ThrowIfNull(instance, nameof(instance)); + Guard.ThrowIfNull(propertyInfo, nameof(propertyInfo)); + + this.instance = instance; + this.propertyInfo = propertyInfo; + } + + public object Value + { + get { return propertyInfo.GetValue(instance); } + set + { + propertyInfo.SetValue(instance, value); + } + } + + public Type PropertyType => propertyInfo.PropertyType; + public string Name => propertyInfo.Name; + } +} \ No newline at end of file diff --git a/Perspex.Xaml/DataBinding/DataContextChangeSynchronizer.cs b/Perspex.Xaml/DataBinding/DataContextChangeSynchronizer.cs new file mode 100644 index 0000000000..739f7d26b5 --- /dev/null +++ b/Perspex.Xaml/DataBinding/DataContextChangeSynchronizer.cs @@ -0,0 +1,113 @@ +namespace Perspex.Xaml.DataBinding +{ + using System; + using System.Diagnostics; + using System.Globalization; + using System.Reflection; + using ChangeTracking; + using Glass; + using OmniXaml.TypeConversion; + + public class DataContextChangeSynchronizer + { + private readonly ITypeConverter targetPropertyTypeConverter; + private readonly TargetBindingEndpoint bindingEndpoint; + private readonly ObservablePropertyBranch sourceEndpoint; + + public DataContextChangeSynchronizer(PerspexObject target, PerspexProperty targetProperty, + PropertyPath sourcePropertyPath, object source, ITypeConverterProvider typeConverterProvider) + { + Guard.ThrowIfNull(target, nameof(target)); + Guard.ThrowIfNull(targetProperty, nameof(targetProperty)); + Guard.ThrowIfNull(sourcePropertyPath, nameof(sourcePropertyPath)); + Guard.ThrowIfNull(source, nameof(source)); + Guard.ThrowIfNull(typeConverterProvider, nameof(typeConverterProvider)); + + bindingEndpoint = new TargetBindingEndpoint(target, targetProperty); + sourceEndpoint = new ObservablePropertyBranch(source, sourcePropertyPath); + targetPropertyTypeConverter = typeConverterProvider.GetTypeConverter(targetProperty.PropertyType); + } + + private bool CanAssignWithoutConversion + { + get + { + var sourceTypeInfo = sourceEndpoint.Type.GetTypeInfo(); + var targetTypeInfo = bindingEndpoint.Property.PropertyType.GetTypeInfo(); + var compatible = targetTypeInfo.IsAssignableFrom(sourceTypeInfo); + return compatible; + } + } + + public void SubscribeModelToUI() + { + bindingEndpoint.Object.GetObservable(bindingEndpoint.Property).Subscribe(UpdateModelFromUI); + } + + public void SubscribeUIToModel() + { + sourceEndpoint.Changed.Subscribe(_ => UpdateUIFromModel()); + UpdateUIFromModel(); + } + + private void UpdateUIFromModel() + { + object contextGetter = sourceEndpoint.Value; + SetCompatibleValue(contextGetter, bindingEndpoint.Property.PropertyType, o => bindingEndpoint.Object.SetValue(bindingEndpoint.Property, o)); + } + + private void SetCompatibleValue(object originalValue, Type targetType, Action setValueFunc) + { + if (originalValue == null) + { + setValueFunc(null); + } + else + { + if (CanAssignWithoutConversion) + { + setValueFunc(originalValue); + } + else + { + var synchronizationOk = false; + + if (targetPropertyTypeConverter != null) + { + if (targetPropertyTypeConverter.CanConvertTo(null, targetType)) + { + object convertedValue = targetPropertyTypeConverter.ConvertTo(null, CultureInfo.InvariantCulture, originalValue, + targetType); + + if (convertedValue != null) + { + setValueFunc(convertedValue); + synchronizationOk = true; + } + } + } + + if (!synchronizationOk) + { + LogCannotConvertError(originalValue); + } + } + } + } + + private void UpdateModelFromUI(object valueFromUI) + { + SetCompatibleValue(valueFromUI, sourceEndpoint.Type, o => sourceEndpoint.Value = o); + } + + private void LogCannotConvertError(object value) + { + Contract.Requires(value != null); + + var loggableValue = value.ToString(); + var valueToWrite = string.IsNullOrWhiteSpace(loggableValue) ? "'(empty/whitespace string)'" : loggableValue; + + Debug.WriteLine("Cannot convert value {0} ({1}) to {2}", valueToWrite, value.GetType(), bindingEndpoint.Property.PropertyType); + } + } +} \ No newline at end of file diff --git a/Perspex.Xaml/DataBinding/IPerspexPropertyBinder.cs b/Perspex.Xaml/DataBinding/IPerspexPropertyBinder.cs new file mode 100644 index 0000000000..13cc8c6da0 --- /dev/null +++ b/Perspex.Xaml/DataBinding/IPerspexPropertyBinder.cs @@ -0,0 +1,11 @@ +namespace Perspex.Xaml.DataBinding +{ + using System.Collections.Generic; + + public interface IPerspexPropertyBinder + { + XamlBinding GetBinding(PerspexObject po, PerspexProperty pp); + IEnumerable GetBindings(PerspexObject source); + XamlBinding Create(XamlBindingDefinition xamlBinding); + } +} \ No newline at end of file diff --git a/Perspex.Xaml/DataBinding/PerspexPropertyBinder.cs b/Perspex.Xaml/DataBinding/PerspexPropertyBinder.cs new file mode 100644 index 0000000000..00be05674c --- /dev/null +++ b/Perspex.Xaml/DataBinding/PerspexPropertyBinder.cs @@ -0,0 +1,56 @@ +namespace Perspex.Xaml.DataBinding +{ + using System; + using System.Collections.Generic; + using System.Linq; + using OmniXaml.TypeConversion; + + public class PerspexPropertyBinder : IPerspexPropertyBinder + { + private readonly ITypeConverterProvider typeConverterProvider; + + private readonly HashSet bindings; + + public PerspexPropertyBinder(ITypeConverterProvider typeConverterProvider) + { + this.typeConverterProvider = typeConverterProvider; + bindings = new HashSet(); + } + + public XamlBinding GetBinding(PerspexObject po, PerspexProperty pp) + { + return bindings.First(xamlBinding => xamlBinding.Target == po && xamlBinding.TargetProperty == pp); + } + + public IEnumerable GetBindings(PerspexObject source) + { + return from binding in bindings + where binding.Target == source + select binding; + } + + public XamlBinding Create(XamlBindingDefinition xamlBinding) + { + if (xamlBinding.Target == null) + { + throw new InvalidOperationException(); + } + + if (xamlBinding.TargetProperty == null) + { + throw new InvalidOperationException(); + } + + var binding = new XamlBinding(typeConverterProvider) + { + BindingMode = xamlBinding.BindingMode, + SourcePropertyPath = xamlBinding.SourcePropertyPath, + Target = xamlBinding.Target, + TargetProperty = xamlBinding.TargetProperty + }; + + bindings.Add(binding); + return binding; + } + } +} \ No newline at end of file diff --git a/Perspex.Xaml/DataBinding/SourceBindingEndpoint.cs b/Perspex.Xaml/DataBinding/SourceBindingEndpoint.cs new file mode 100644 index 0000000000..cc5ac9c2f5 --- /dev/null +++ b/Perspex.Xaml/DataBinding/SourceBindingEndpoint.cs @@ -0,0 +1,21 @@ +namespace Perspex.Xaml.DataBinding +{ + using System; + using System.ComponentModel; + + public class SourceBindingEndpoint + { + public Type PropertyType { get; } + public INotifyPropertyChanged Source { get; } + public dynamic PropertyGetter { get; } + public Delegate PropertySetter { get; } + + public SourceBindingEndpoint(INotifyPropertyChanged source, Type propertyType, dynamic propertyGetter, Delegate propertySetter) + { + this.Source = source; + this.PropertyType = propertyType; + this.PropertyGetter = propertyGetter; + this.PropertySetter = propertySetter; + } + } +} \ No newline at end of file diff --git a/Perspex.Xaml/DataBinding/TargetBindingEndpoint.cs b/Perspex.Xaml/DataBinding/TargetBindingEndpoint.cs new file mode 100644 index 0000000000..87d3f8ce0d --- /dev/null +++ b/Perspex.Xaml/DataBinding/TargetBindingEndpoint.cs @@ -0,0 +1,14 @@ +namespace Perspex.Xaml.DataBinding +{ + public class TargetBindingEndpoint + { + public PerspexObject Object { get; } + public PerspexProperty Property { get; } + + public TargetBindingEndpoint(PerspexObject obj, PerspexProperty property) + { + Object = obj; + Property = property; + } + } +} \ No newline at end of file diff --git a/Perspex.Xaml/DataBinding/XamlBinding.cs b/Perspex.Xaml/DataBinding/XamlBinding.cs new file mode 100644 index 0000000000..ce560d052f --- /dev/null +++ b/Perspex.Xaml/DataBinding/XamlBinding.cs @@ -0,0 +1,68 @@ +namespace Perspex.Xaml.DataBinding +{ + using System; + using System.Diagnostics; + using ChangeTracking; + using OmniXaml.TypeConversion; + + public class XamlBinding + { + private readonly ITypeConverterProvider typeConverterProvider; + + public PerspexObject Target { get; set; } + public PerspexProperty TargetProperty { get; set; } + public PropertyPath SourcePropertyPath { get; set; } + public BindingMode BindingMode { get; set; } + + public XamlBinding(ITypeConverterProvider typeConverterProvider) + { + this.typeConverterProvider = typeConverterProvider; + } + + public void Bind(object dataContext) + { + if (dataContext == null) + { + return; + } + + try + { + if (BindingMode == BindingMode.TwoWay) + { + var changeSynchronizer = new DataContextChangeSynchronizer( + Target, + TargetProperty, + SourcePropertyPath, + dataContext, + typeConverterProvider); + + changeSynchronizer.SubscribeUIToModel(); + changeSynchronizer.SubscribeModelToUI(); + } + + if (BindingMode == BindingMode.OneWay) + { + var subscriptionHandler = new DataContextChangeSynchronizer( + Target, + TargetProperty, + SourcePropertyPath, + dataContext, + typeConverterProvider); + + subscriptionHandler.SubscribeUIToModel(); + } + + if (BindingMode == BindingMode.OneWayToSource) + { + var subscriptionHandler = new DataContextChangeSynchronizer(Target, TargetProperty, SourcePropertyPath, dataContext, typeConverterProvider); + subscriptionHandler.SubscribeModelToUI(); + } + } + catch (Exception e) + { + Debug.WriteLine(e); + } + } + } +} \ No newline at end of file diff --git a/Perspex.Xaml/DataBinding/XamlBindingDefinition.cs b/Perspex.Xaml/DataBinding/XamlBindingDefinition.cs new file mode 100644 index 0000000000..26847901b7 --- /dev/null +++ b/Perspex.Xaml/DataBinding/XamlBindingDefinition.cs @@ -0,0 +1,29 @@ +namespace Perspex.Xaml.DataBinding +{ + using ChangeTracking; + using Controls; + + public class XamlBindingDefinition + { + private PropertyPath sourcePropertyPath; + private BindingMode bindingMode; + private readonly Control target; + private readonly PerspexProperty targetProperty; + + public XamlBindingDefinition(Control target, PerspexProperty targetProperty, PropertyPath sourcePropertyPath, BindingMode bindingMode) + { + this.target = target; + this.targetProperty = targetProperty; + this.sourcePropertyPath = sourcePropertyPath; + this.bindingMode = bindingMode; + } + + public Control Target => target; + + public PerspexProperty TargetProperty => targetProperty; + + public PropertyPath SourcePropertyPath => sourcePropertyPath; + + public BindingMode BindingMode => bindingMode; + } +} \ No newline at end of file diff --git a/Perspex.Xaml/HighLevel/IResourceProvider.cs b/Perspex.Xaml/HighLevel/IResourceProvider.cs new file mode 100644 index 0000000000..151a06d60f --- /dev/null +++ b/Perspex.Xaml/HighLevel/IResourceProvider.cs @@ -0,0 +1,10 @@ +namespace Perspex.Xaml.HighLevel +{ + using System; + using System.IO; + + public interface IResourceProvider + { + Stream GetStream(Uri uri); + } +} \ No newline at end of file diff --git a/Perspex.Xaml/HighLevel/PerspexLoaderFactory.cs b/Perspex.Xaml/HighLevel/PerspexLoaderFactory.cs new file mode 100644 index 0000000000..aafad7c322 --- /dev/null +++ b/Perspex.Xaml/HighLevel/PerspexLoaderFactory.cs @@ -0,0 +1,20 @@ +namespace Perspex.Xaml.HighLevel +{ + using Context; + using OmniXaml; + + public static class PerspexWiringContextFactory + { + private static IWiringContext context; + + public static IWiringContext GetContext(ITypeFactory factory) + { + if (context == null) + { + context = new PerspexWiringContext(factory); + } + + return context; + } + } +} \ No newline at end of file diff --git a/Perspex.Xaml/HighLevel/PerspexObjectAssemblerFactory.cs b/Perspex.Xaml/HighLevel/PerspexObjectAssemblerFactory.cs new file mode 100644 index 0000000000..6de80663fb --- /dev/null +++ b/Perspex.Xaml/HighLevel/PerspexObjectAssemblerFactory.cs @@ -0,0 +1,21 @@ +namespace Perspex.Xaml.HighLevel +{ + using OmniXaml; + using Context; + using OmniXaml.ObjectAssembler; + + public class PerspexObjectAssemblerFactory : IObjectAssemblerFactory + { + private readonly WiringContext context; + + public PerspexObjectAssemblerFactory(WiringContext context) + { + this.context = context; + } + + public IObjectAssembler CreateAssembler(ObjectAssemblerSettings settings) + { + return new PerspexObjectAssembler(context, settings); + } + } +} \ No newline at end of file diff --git a/Perspex.Xaml/MarkupExtensions/BindingExtension.cs b/Perspex.Xaml/MarkupExtensions/BindingExtension.cs new file mode 100644 index 0000000000..e76839ab46 --- /dev/null +++ b/Perspex.Xaml/MarkupExtensions/BindingExtension.cs @@ -0,0 +1,41 @@ +namespace Perspex.Xaml.MarkupExtensions +{ + using System.Linq; + using Controls; + using DataBinding; + using DataBinding.ChangeTracking; + using OmniXaml; + + public class BindingExtension : MarkupExtension + { + public BindingExtension() + { + } + + public BindingExtension(string path) + { + Path = path; + } + + public override object ProvideValue(MarkupExtensionContext extensionContext) + { + var target = extensionContext.TargetObject as Control; + var targetProperty = extensionContext.TargetProperty; + var targetPropertyName = targetProperty.Name; + var perspexProperty = target.GetRegisteredProperties().First(property => property.Name == targetPropertyName); + + return new XamlBindingDefinition + ( + target, + perspexProperty, + new PropertyPath(Path), + Mode == BindingMode.Default ? BindingMode.OneWay : Mode + ); + } + + /// The source path (for CLR bindings). + public string Path { get; set; } + + public BindingMode Mode { get; set; } + } +} \ No newline at end of file diff --git a/Perspex.Xaml/MarkupExtensions/TypeExtension.cs b/Perspex.Xaml/MarkupExtensions/TypeExtension.cs new file mode 100644 index 0000000000..ab5dc16e5e --- /dev/null +++ b/Perspex.Xaml/MarkupExtensions/TypeExtension.cs @@ -0,0 +1,45 @@ +namespace Perspex.Xaml.MarkupExtensions +{ + using System; + using Glass; + using OmniXaml; + using OmniXaml.Attributes; + using OmniXaml.Typing; + + [ContentProperty("TargetType")] + public class TypeExtension : MarkupExtension + { + public Type Type { get; set; } + + public TypeExtension() + { + } + + public TypeExtension(Type type) + { + Type = type; + } + + public string TypeName { get; set; } + + private Type ResolveFromString(string typeLocator, IXamlTypeRepository typeRepository) + { + Guard.ThrowIfNull(typeLocator, nameof(typeLocator)); + + var prefixAndType = typeLocator.Dicotomize(':'); + + var xamlType = typeRepository.GetByPrefix(prefixAndType.Item1, prefixAndType.Item2); + return xamlType.UnderlyingType; + } + + public override object ProvideValue(MarkupExtensionContext markupExtensionContext) + { + if (Type != null) + { + return Type; + } + + return ResolveFromString(TypeName, markupExtensionContext.TypeRepository); + } + } +} \ No newline at end of file diff --git a/Perspex.Xaml/Perspex.Xaml.csproj b/Perspex.Xaml/Perspex.Xaml.csproj new file mode 100644 index 0000000000..feddbab0c2 --- /dev/null +++ b/Perspex.Xaml/Perspex.Xaml.csproj @@ -0,0 +1,157 @@ + + + + + 12.0 + Debug + AnyCPU + {3E53A01A-B331-47F3-B828-4A5717E77A24} + Library + Properties + Perspex.Xaml + Perspex.Xaml + en-US + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Profile44 + v4.6 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {d211e587-d8bc-45b9-95a4-f297c8fa5200} + Perspex.Animation + + + {B09B78D8-9B26-48B0-9149-D64A2F120F3F} + Perspex.Base + + + {D2221C82-4A25-4583-9B43-D791E3F6820C} + Perspex.Controls + + + {62024b2d-53eb-4638-b26b-85eeaa54866e} + Perspex.Input + + + {6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b} + Perspex.Interactivity + + + {42472427-4774-4c81-8aff-9f27b8e31721} + Perspex.Layout + + + {eb582467-6abb-43a1-b052-e981ba910e3a} + Perspex.SceneGraph + + + {f1baa01a-f176-4c6a-b39d-5b40bb1b148f} + Perspex.Styling + + + + + ..\packages\Glass.1.4.2.0\lib\portable-net451+win81+wpa81\Glass.dll + True + + + ..\packages\OmniXaml.1.4.2.0\lib\portable-net451+win81+wpa81\OmniXaml.dll + True + + + ..\packages\reactiveui-core.6.5.0\lib\Portable-Net45+Win8+WP8+WPA81\ReactiveUI.dll + True + + + ..\packages\Serilog.1.5.6\lib\portable-net45+win+wpa81+wp80+MonoAndroid10+MonoTouch10\Serilog.dll + True + + + ..\packages\Splat.1.6.2\lib\Portable-net45+win+wpa81+wp80\Splat.dll + True + + + ..\packages\Sprache.SuperJMN.2.0.0.46\lib\portable-net451+win81+wpa81\Sprache.dll + True + + + ..\packages\Rx-Core.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Core.dll + True + + + ..\packages\Rx-Interfaces.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Interfaces.dll + True + + + ..\packages\Rx-Linq.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Linq.dll + True + + + ..\packages\Rx-PlatformServices.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.PlatformServices.dll + True + + + + + \ No newline at end of file diff --git a/Perspex.Xaml/Perspex.Xaml.previous.nugetreferenceswitcher b/Perspex.Xaml/Perspex.Xaml.previous.nugetreferenceswitcher new file mode 100644 index 0000000000..92bfcef4e9 --- /dev/null +++ b/Perspex.Xaml/Perspex.Xaml.previous.nugetreferenceswitcher @@ -0,0 +1,2 @@ +Glass ../../GitHub/OmniXAML/Glass/Glass.csproj ../packages/OmniXaml.1.0.11/lib/portable-net451+win81/Glass.dll +OmniXaml ../../GitHub/OmniXAML/OmniXaml/OmniXaml/OmniXaml.csproj ../packages/OmniXaml.1.0.11/lib/portable-net451+win81/OmniXaml.dll diff --git a/Perspex.Xaml/Properties/AssemblyInfo.cs b/Perspex.Xaml/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..a67f2c39b2 --- /dev/null +++ b/Perspex.Xaml/Properties/AssemblyInfo.cs @@ -0,0 +1,30 @@ +using System.Resources; +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("Perspex.Xaml")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Perspex.Xaml")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: NeutralResourcesLanguage("en")] + +// 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 Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Perspex.Xaml/Templates/Template.cs b/Perspex.Xaml/Templates/Template.cs new file mode 100644 index 0000000000..def98035f5 --- /dev/null +++ b/Perspex.Xaml/Templates/Template.cs @@ -0,0 +1,7 @@ +namespace Perspex.Xaml.Templates +{ + public class Template + { + public TemplateContent Content { get; set; } + } +} \ No newline at end of file diff --git a/Perspex.Xaml/Templates/TemplateContent.cs b/Perspex.Xaml/Templates/TemplateContent.cs new file mode 100644 index 0000000000..76a5c4ff88 --- /dev/null +++ b/Perspex.Xaml/Templates/TemplateContent.cs @@ -0,0 +1,31 @@ +namespace Perspex.Xaml.Templates +{ + using System.Collections.Generic; + using Context; + using OmniXaml; + using Perspex.Controls; + + public class TemplateContent + { + private readonly IEnumerable nodes; + private readonly IWiringContext context; + + public TemplateContent(IEnumerable nodes, IWiringContext context) + { + this.nodes = nodes; + this.context = context; + } + + public Control Load() + { + var assembler = new PerspexObjectAssembler(context); + + foreach (var xamlNode in nodes) + { + assembler.Process(xamlNode); + } + + return (Control)assembler.Result; + } + } +} \ No newline at end of file diff --git a/Perspex.Xaml/Templates/TemplateLoader.cs b/Perspex.Xaml/Templates/TemplateLoader.cs new file mode 100644 index 0000000000..f3cd4e000a --- /dev/null +++ b/Perspex.Xaml/Templates/TemplateLoader.cs @@ -0,0 +1,13 @@ +namespace Perspex.Xaml.Templates +{ + using System.Collections.Generic; + using OmniXaml; + + public class TemplateLoader : IDeferredLoader + { + public object Load(IEnumerable nodes, IWiringContext context) + { + return new TemplateContent(nodes, context); + } + } +} \ No newline at end of file diff --git a/Perspex.Xaml/Templates/XamlDataTemplate.cs b/Perspex.Xaml/Templates/XamlDataTemplate.cs new file mode 100644 index 0000000000..cca2ed0172 --- /dev/null +++ b/Perspex.Xaml/Templates/XamlDataTemplate.cs @@ -0,0 +1,41 @@ +namespace Perspex.Xaml.Templates +{ + using System; + using Controls.Templates; + using OmniXaml.Attributes; + using Controls; + + [ContentProperty("Content")] + public class XamlDataTemplate : IDataTemplate + { + private bool MyMatch(object data) + { + if (DataType == null) + { + throw new InvalidOperationException("XAML DataTemplates must have a DataType"); + } + + return DataType == data.GetType(); + } + + private Control CreateVisualTreeForItem(object data) + { + var visualTreeForItem = Content.Load(); + visualTreeForItem.DataContext = data; + return visualTreeForItem; + } + + public Type DataType { get; set; } + + public TemplateContent Content { get; set; } + public IControl Build(object param) + { + return CreateVisualTreeForItem(param); + } + + public bool Match(object data) + { + return MyMatch(data); + } + } +} \ No newline at end of file diff --git a/Perspex.Xaml/app.config b/Perspex.Xaml/app.config new file mode 100644 index 0000000000..3bc5982bec --- /dev/null +++ b/Perspex.Xaml/app.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/Perspex.Xaml/packages.config b/Perspex.Xaml/packages.config new file mode 100644 index 0000000000..f087f8d34c --- /dev/null +++ b/Perspex.Xaml/packages.config @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Perspex.sln b/Perspex.sln index ed90a33b4a..d3f568f5a9 100644 --- a/Perspex.sln +++ b/Perspex.sln @@ -57,6 +57,16 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Input.UnitTests", " EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Direct2D1.UnitTests", "Tests\Perspex.Direct2D1.UnitTests\Perspex.Direct2D1.UnitTests.csproj", "{EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Xaml", "Perspex.Xaml\Perspex.Xaml.csproj", "{3E53A01A-B331-47F3-B828-4A5717E77A24}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Xaml.Desktop", "Perspex.Xaml.Desktop\Perspex.Xaml.Desktop.csproj", "{EB468C39-AAC4-4963-A7B2-0A405EA63EDD}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XamlTestApplication", "XamlTestApplication\XamlTestApplication.csproj", "{78CAFE33-DBEB-4132-8A28-81CFE8A4933C}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "XAML", "XAML", "{8B6A8209-894F-4BA1-B880-965FD453982C}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test Applications", "Test Applications", "{9B9E3891-2366-4253-A952-D08BCEB71098}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -159,12 +169,25 @@ Global {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Debug|Any CPU.Build.0 = Debug|Any CPU {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|Any CPU.ActiveCfg = Release|Any CPU {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|Any CPU.Build.0 = Release|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|Any CPU.Build.0 = Release|Any CPU + {EB468C39-AAC4-4963-A7B2-0A405EA63EDD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EB468C39-AAC4-4963-A7B2-0A405EA63EDD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EB468C39-AAC4-4963-A7B2-0A405EA63EDD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EB468C39-AAC4-4963-A7B2-0A405EA63EDD}.Release|Any CPU.Build.0 = Release|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {811A76CF-1CF6-440F-963B-BBE31BD72A82} = {B39A8919-9F95-48FE-AD7B-76E08B509888} + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72} = {9B9E3891-2366-4253-A952-D08BCEB71098} {3E908F67-5543-4879-A1DC-08EACE79B3CD} = {B39A8919-9F95-48FE-AD7B-76E08B509888} {47ECDF59-DEF8-4C53-87B1-2098A3429059} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} {5CCB5571-7C30-4E7D-967D-0E2158EBD91F} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} @@ -176,5 +199,8 @@ Global {DABFD304-D6A4-4752-8123-C2CCF7AC7831} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} {AC18926A-E784-40FE-B09D-BB0FE2B599F0} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} + {3E53A01A-B331-47F3-B828-4A5717E77A24} = {8B6A8209-894F-4BA1-B880-965FD453982C} + {EB468C39-AAC4-4963-A7B2-0A405EA63EDD} = {8B6A8209-894F-4BA1-B880-965FD453982C} + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C} = {9B9E3891-2366-4253-A952-D08BCEB71098} EndGlobalSection EndGlobal diff --git a/XamlTestApplication/App.config b/XamlTestApplication/App.config new file mode 100644 index 0000000000..2e8edd3a62 --- /dev/null +++ b/XamlTestApplication/App.config @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/XamlTestApplication/App.cs b/XamlTestApplication/App.cs new file mode 100644 index 0000000000..4762a4892e --- /dev/null +++ b/XamlTestApplication/App.cs @@ -0,0 +1,16 @@ +namespace XamlTestApplication +{ + using System; + using Perspex; + using Perspex.Themes.Default; + + public class App : Application + { + public App() + { + this.RegisterServices(); + this.InitializeSubsystems((int)Environment.OSVersion.Platform); + this.Styles = new DefaultTheme(); + } + } +} diff --git a/XamlTestApplication/MainViewModel.cs b/XamlTestApplication/MainViewModel.cs new file mode 100644 index 0000000000..57db4848c1 --- /dev/null +++ b/XamlTestApplication/MainViewModel.cs @@ -0,0 +1,49 @@ +namespace XamlTestApplication +{ + using System.Collections.Generic; + using ReactiveUI; + + public class MainViewModel : ReactiveObject + { + private string name; + + public MainViewModel() + { + Name = "José Manuel"; + People = new List + { + new Person("a little bit of Monica in my life"), + new Person("a little bit of Erica by my side"), + new Person("a little bit of Rita is all I need"), + new Person("a little bit of Tina is what I see"), + new Person("a little bit of Sandra in the sun"), + new Person("a little bit of Mary all night long"), + new Person("a little bit of Jessica here I am"), + }; + } + + public string Name + { + get { return name; } + set { this.RaiseAndSetIfChanged(ref name, value); } + } + + public List People { get; set; } + } + + public class Person + { + private string name; + + public Person(string name) + { + this.name = name; + } + + public string Name + { + get { return name; } + set { name = value; } + } + } +} \ No newline at end of file diff --git a/XamlTestApplication/Program.cs b/XamlTestApplication/Program.cs new file mode 100644 index 0000000000..5b8f3ba0ba --- /dev/null +++ b/XamlTestApplication/Program.cs @@ -0,0 +1,68 @@ +#if PERSPEX_GTK +using Perspex.Gtk; +#endif + +namespace XamlTestApplication +{ + using System; + using System.Diagnostics; + using System.Windows.Threading; + using Glass; + using OmniXaml.AppServices.Mvvm; + using OmniXaml.AppServices.NetCore; + using Perspex; + using Perspex.Collections; + using Perspex.Controls; + using Perspex.Controls.Templates; + using Perspex.Input; + using Perspex.Xaml.Desktop; + using ReactiveUI; + + class Item + { + public string Name { get; set; } + public string Value { get; set; } + } + + class Node + { + public Node() + { + this.Children = new PerspexList(); + } + + public string Name { get; set; } + public PerspexList Children { get; set; } + } + + class Program + { + static void Main() + { + var foo = Dispatcher.CurrentDispatcher; + + App application = new App + { + DataTemplates = new DataTemplates + { + new TreeDataTemplate( + x => new TextBlock { Text = x.Name }, + x => x.Children, + x => true), + }, + }; + + var testCommand = ReactiveCommand.Create(); + testCommand.Subscribe(_ => Debug.WriteLine("Test command executed.")); + + var typeFactory = new PerspexInflatableTypeFactory(); + + var viewFactory = new ViewFactory(typeFactory); + viewFactory.RegisterViews(ViewRegistration.FromTypes(Assemblies.AssembliesInAppFolder.AllExportedTypes())); + + var window = (Window) viewFactory.GetWindow("Main"); + window.Show(); + Application.Current.Run(window); + } + } +} diff --git a/XamlTestApplication/Properties/AssemblyInfo.cs b/XamlTestApplication/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..5e8029017d --- /dev/null +++ b/XamlTestApplication/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +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("TestApplication")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("TestApplication")] +[assembly: AssemblyCopyright("Copyright © 2013")] +[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("f8dad012-f4ec-4b63-b64f-320901338290")] + +// 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 Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/XamlTestApplication/Views/MainWindow.cs b/XamlTestApplication/Views/MainWindow.cs new file mode 100644 index 0000000000..7196f10919 --- /dev/null +++ b/XamlTestApplication/Views/MainWindow.cs @@ -0,0 +1,10 @@ +namespace XamlTestApplication.Views +{ + using OmniXaml.AppServices.Mvvm; + using Perspex.Xaml.Desktop; + + [ViewToken("Main", typeof(MainWindow))] + public class MainWindow : PerspexWindow + { + } +} \ No newline at end of file diff --git a/XamlTestApplication/Views/MainWindow.xaml b/XamlTestApplication/Views/MainWindow.xaml new file mode 100644 index 0000000000..0a36b8fa67 --- /dev/null +++ b/XamlTestApplication/Views/MainWindow.xaml @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/XamlTestApplication/XamlTestApplication.csproj b/XamlTestApplication/XamlTestApplication.csproj new file mode 100644 index 0000000000..a5f354650f --- /dev/null +++ b/XamlTestApplication/XamlTestApplication.csproj @@ -0,0 +1,220 @@ + + + + + Debug + AnyCPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C} + WinExe + Properties + XamlTestApplication + XamlTestApplication + v4.6 + 512 + + + + + + AnyCPU + true + full + false + bin\Debug\ + TRACE;DEBUG + prompt + 4 + true + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Glass.1.4.2.0\lib\portable-net451+win81+wpa81\Glass.dll + True + + + ..\packages\Perspex.1.0.1\lib\portable-net451+win81+wpa81\NGenerics.dll + True + + + ..\packages\OmniXaml.1.4.2.0\lib\portable-net451+win81+wpa81\OmniXaml.dll + True + + + ..\packages\OmniXaml.AppServices.1.4.2.0\lib\portable-net451+win81+wpa81\OmniXaml.AppServices.dll + True + + + ..\packages\OmniXaml.AppServices.Mvvm.1.4.2.0\lib\portable-net451+win81+wpa81\OmniXaml.AppServices.Mvvm.dll + True + + + ..\packages\OmniXaml.AppServices.NetCore.1.4.2.0\lib\net46\OmniXaml.AppServices.NetCore.dll + True + + + ..\packages\reactiveui-core.6.4.0.1\lib\Net45\ReactiveUI.dll + True + + + ..\packages\Serilog.1.5.6\lib\net45\Serilog.dll + True + + + ..\packages\Serilog.1.5.6\lib\net45\Serilog.FullNetFx.dll + True + + + False + $(SharpDXPackageBinDir)\SharpDX.dll + + + False + $(SharpDXPackageBinDir)\SharpDX.Direct2D1.dll + + + False + $(SharpDXPackageBinDir)\SharpDX.DXGI.dll + + + ..\packages\Splat.1.6.2\lib\Net45\Splat.dll + True + + + ..\packages\Sprache.SuperJMN.2.0.0.46\lib\portable-net451+win81+wpa81\Sprache.dll + True + + + + + + ..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll + True + + + ..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll + True + + + ..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll + True + + + ..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll + True + + + ..\packages\Rx-XAML.2.2.5\lib\net45\System.Reactive.Windows.Threading.dll + True + + + + + + + + + + + + + + + + + + + + + {d211e587-d8bc-45b9-95a4-f297c8fa5200} + Perspex.Animation + + + {799a7bb5-3c2c-48b6-85a7-406a12c420da} + Perspex.Application + + + {b09b78d8-9b26-48b0-9149-d64a2f120f3f} + Perspex.Base + + + {d2221c82-4a25-4583-9b43-d791e3f6820c} + Perspex.Controls + + + {62024b2d-53eb-4638-b26b-85eeaa54866e} + Perspex.Input + + + {6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b} + Perspex.Interactivity + + + {42472427-4774-4c81-8aff-9f27b8e31721} + Perspex.Layout + + + {eb582467-6abb-43a1-b052-e981ba910e3a} + Perspex.SceneGraph + + + {f1baa01a-f176-4c6a-b39d-5b40bb1b148f} + Perspex.Styling + + + {3e10a5fa-e8da-48b1-ad44-6a5b6cb7750f} + Perspex.Themes.Default + + + {eb468c39-aac4-4963-a7b2-0a405ea63edd} + Perspex.Xaml.Desktop + + + {3e53a01a-b331-47f3-b828-4a5717e77a24} + Perspex.Xaml + + + {3e908f67-5543-4879-a1dc-08eace79b3cd} + Perspex.Direct2D1 + + + {811a76cf-1cf6-440f-963b-bbe31bd72a82} + Perspex.Win32 + + + + + PreserveNewest + + + + + + Designer + PreserveNewest + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/XamlTestApplication/XamlTestApplication.previous.nugetreferenceswitcher b/XamlTestApplication/XamlTestApplication.previous.nugetreferenceswitcher new file mode 100644 index 0000000000..92bfcef4e9 --- /dev/null +++ b/XamlTestApplication/XamlTestApplication.previous.nugetreferenceswitcher @@ -0,0 +1,2 @@ +Glass ../../GitHub/OmniXAML/Glass/Glass.csproj ../packages/OmniXaml.1.0.11/lib/portable-net451+win81/Glass.dll +OmniXaml ../../GitHub/OmniXAML/OmniXaml/OmniXaml/OmniXaml.csproj ../packages/OmniXaml.1.0.11/lib/portable-net451+win81/OmniXaml.dll diff --git a/XamlTestApplication/github_icon.png b/XamlTestApplication/github_icon.png new file mode 100644 index 0000000000..ed4f82f847 Binary files /dev/null and b/XamlTestApplication/github_icon.png differ diff --git a/XamlTestApplication/packages.config b/XamlTestApplication/packages.config new file mode 100644 index 0000000000..c104501734 --- /dev/null +++ b/XamlTestApplication/packages.config @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file