diff options
author | Stephane Delcroix <stephane@delcroix.org> | 2016-09-08 20:39:05 +0200 |
---|---|---|
committer | Jason Smith <jason.smith@xamarin.com> | 2016-09-08 11:39:05 -0700 |
commit | 85426c5d9495eb1d55b3128bf97e50c68a73b53f (patch) | |
tree | 2f81e5868ce61eb90d15c6c51a354603b8395627 /Xamarin.Forms.Platform.WinRT | |
parent | 11326e1c182b3ff5c3d82c6ef7d09c193bc19891 (diff) | |
download | xamarin-forms-85426c5d9495eb1d55b3128bf97e50c68a73b53f.tar.gz xamarin-forms-85426c5d9495eb1d55b3128bf97e50c68a73b53f.tar.bz2 xamarin-forms-85426c5d9495eb1d55b3128bf97e50c68a73b53f.zip |
Native Bindings (#278)
* [C, I, A, W] Support Native Bindings
* fix tabs
Diffstat (limited to 'Xamarin.Forms.Platform.WinRT')
6 files changed, 178 insertions, 1 deletions
diff --git a/Xamarin.Forms.Platform.WinRT/FrameworkElementExtensions.cs b/Xamarin.Forms.Platform.WinRT/FrameworkElementExtensions.cs index eb040e02..f94f3d62 100644 --- a/Xamarin.Forms.Platform.WinRT/FrameworkElementExtensions.cs +++ b/Xamarin.Forms.Platform.WinRT/FrameworkElementExtensions.cs @@ -128,5 +128,21 @@ namespace Xamarin.Forms.Platform.WinRT return foregroundProperty; } + + internal static IEnumerable<T> GetChildren<T>(this DependencyObject parent) where T : DependencyObject + { + int myChildrenCount = VisualTreeHelper.GetChildrenCount(parent); + for (int i = 0; i < myChildrenCount; i++) + { + var child = VisualTreeHelper.GetChild(parent, i); + if (child is T) + yield return child as T; + else + { + foreach (var subChild in child.GetChildren<T>()) + yield return subChild; + } + } + } } }
\ No newline at end of file diff --git a/Xamarin.Forms.Platform.WinRT/NativeBindingExtensions.cs b/Xamarin.Forms.Platform.WinRT/NativeBindingExtensions.cs new file mode 100644 index 00000000..cc88c87e --- /dev/null +++ b/Xamarin.Forms.Platform.WinRT/NativeBindingExtensions.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using Windows.UI.Xaml; +using static System.String; +#if WINDOWS_UWP + +namespace Xamarin.Forms.Platform.UWP +#else + +namespace Xamarin.Forms.Platform.WinRT +#endif +{ + public static class NativeBindingExtensions + { + public static void SetBinding(this FrameworkElement view, string propertyName, BindingBase bindingBase, string updateSourceEventName = null) + { + var binding = bindingBase as Binding; + updateSourceEventName = updateSourceEventName ?? binding?.UpdateSourceEventName; + + if (IsNullOrEmpty(updateSourceEventName)) + { + NativePropertyListener nativePropertyListener = null; + if (bindingBase.Mode == BindingMode.TwoWay) + nativePropertyListener = new NativePropertyListener(view, propertyName); + + NativeBindingHelpers.SetBinding(view, propertyName, bindingBase, nativePropertyListener as INotifyPropertyChanged); + return; + } + + NativeEventWrapper eventE = null; + if (binding.Mode == BindingMode.TwoWay && !(view is INotifyPropertyChanged)) + eventE = new NativeEventWrapper(view, propertyName, updateSourceEventName); + + NativeBindingHelpers.SetBinding(view, propertyName, binding, eventE); + } + + public static void SetBinding(this FrameworkElement view, BindableProperty targetProperty, BindingBase binding) + { + NativeBindingHelpers.SetBinding(view, targetProperty, binding); + } + + public static void SetValue(this FrameworkElement target, BindableProperty targetProperty, object value) + { + NativeBindingHelpers.SetValue(target, targetProperty, value); + } + + public static void SetBindingContext(this FrameworkElement target, object bindingContext, Func<FrameworkElement, IEnumerable<FrameworkElement>> getChildren = null) + { + NativeBindingHelpers.SetBindingContext(target, bindingContext, getChildren); + } + + internal static void TransferbindablePropertiesToWrapper(this FrameworkElement target, View wrapper) + { + NativeBindingHelpers.TransferBindablePropertiesToWrapper(target, wrapper); + } + } +}
\ No newline at end of file diff --git a/Xamarin.Forms.Platform.WinRT/NativeEventWrapper.cs b/Xamarin.Forms.Platform.WinRT/NativeEventWrapper.cs new file mode 100644 index 00000000..e28ca0eb --- /dev/null +++ b/Xamarin.Forms.Platform.WinRT/NativeEventWrapper.cs @@ -0,0 +1,45 @@ +using System; +using System.ComponentModel; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices.WindowsRuntime; +using Windows.UI.Xaml; + +#if WINDOWS_UWP +namespace Xamarin.Forms.Platform.UWP +#else +namespace Xamarin.Forms.Platform.WinRT +#endif +{ + class NativeEventWrapper : INotifyPropertyChanged + { + static string TargetProperty { get; set; } + static readonly MethodInfo s_handlerinfo = typeof(NativeEventWrapper).GetRuntimeMethods().Single(mi => mi.Name == nameof(OnPropertyChanged) && mi.IsPublic == false); + + public NativeEventWrapper(object target, string targetProperty, string updateSourceEventName) + { + TargetProperty = targetProperty; + try { + var updateSourceEvent = target.GetType().GetRuntimeEvent(updateSourceEventName); + MethodInfo addMethod = updateSourceEvent.AddMethod; + MethodInfo removeMethod = updateSourceEvent.RemoveMethod; + ParameterInfo[] addParameters = addMethod.GetParameters(); + Type delegateType = addParameters[0].ParameterType; + var handlerDelegate = s_handlerinfo.CreateDelegate(delegateType, this); + Func<object, EventRegistrationToken> add = a => (EventRegistrationToken)addMethod.Invoke(target, new object[] { handlerDelegate }); + Action<EventRegistrationToken> remove = t => removeMethod.Invoke(target, new object[] { t }); + WindowsRuntimeMarshal.AddEventHandler(add, remove, s_handlerinfo); + } + catch (Exception) { + Log.Warning(nameof(NativeEventWrapper), "Can not attach NativeEventWrapper."); + } + } + + void OnPropertyChanged(object sender, RoutedEventArgs e) + { + PropertyChanged?.Invoke(sender, new PropertyChangedEventArgs(TargetProperty)); + } + + public event PropertyChangedEventHandler PropertyChanged; + } +} diff --git a/Xamarin.Forms.Platform.WinRT/NativePropertyListener.cs b/Xamarin.Forms.Platform.WinRT/NativePropertyListener.cs new file mode 100644 index 00000000..5a1b294c --- /dev/null +++ b/Xamarin.Forms.Platform.WinRT/NativePropertyListener.cs @@ -0,0 +1,47 @@ +using System; +using System.ComponentModel; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Data; + +#if WINDOWS_UWP +namespace Xamarin.Forms.Platform.UWP +#else +namespace Xamarin.Forms.Platform.WinRT +#endif +{ + class NativePropertyListener : DependencyObject, INotifyPropertyChanged + { + readonly DependencyObject _target; + readonly string _targetProperty; + + public static readonly DependencyProperty TargetPropertyValueProperty = DependencyProperty.Register(nameof(TargetPropertyValue), typeof(object), typeof(NativePropertyListener), new PropertyMetadata(null, OnNativePropertyChanged)); + + public event PropertyChangedEventHandler PropertyChanged; + + public NativePropertyListener(DependencyObject target, string propertyName) + { + _target = target; + _targetProperty = propertyName; + BindingOperations.SetBinding(this, TargetPropertyValueProperty, new Windows.UI.Xaml.Data.Binding() { Source = _target, Path = new PropertyPath(_targetProperty), Mode = Windows.UI.Xaml.Data.BindingMode.OneWay }); + } + + public void Dispose() + { + ClearValue(TargetPropertyValueProperty); + } + + public object TargetPropertyValue + { + get + { + return GetValue(TargetPropertyValueProperty); + } + } + + static void OnNativePropertyChanged(object sender, DependencyPropertyChangedEventArgs args) + { + NativePropertyListener source = (NativePropertyListener)sender; + source?.PropertyChanged?.Invoke(source._target, new PropertyChangedEventArgs(source._targetProperty)); + } + } +}
\ No newline at end of file diff --git a/Xamarin.Forms.Platform.WinRT/NativeViewWrapper.cs b/Xamarin.Forms.Platform.WinRT/NativeViewWrapper.cs index 824f0eed..22cca62e 100644 --- a/Xamarin.Forms.Platform.WinRT/NativeViewWrapper.cs +++ b/Xamarin.Forms.Platform.WinRT/NativeViewWrapper.cs @@ -1,4 +1,5 @@ using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; #if WINDOWS_UWP @@ -17,6 +18,7 @@ namespace Xamarin.Forms.Platform.WinRT ArrangeOverrideDelegate = arrangeOverrideDelegate; MeasureOverrideDelegate = measureOverrideDelegate; NativeElement = nativeElement; + nativeElement.TransferbindablePropertiesToWrapper(this); } public ArrangeOverrideDelegate ArrangeOverrideDelegate { get; set; } @@ -26,5 +28,11 @@ namespace Xamarin.Forms.Platform.WinRT public MeasureOverrideDelegate MeasureOverrideDelegate { get; set; } public FrameworkElement NativeElement { get; } + + protected override void OnBindingContextChanged() + { + NativeElement.SetBindingContext(BindingContext, nv => nv.GetChildren<FrameworkElement>()); + base.OnBindingContextChanged(); + } } }
\ No newline at end of file diff --git a/Xamarin.Forms.Platform.WinRT/Xamarin.Forms.Platform.WinRT.csproj b/Xamarin.Forms.Platform.WinRT/Xamarin.Forms.Platform.WinRT.csproj index fd73aae0..ea456c00 100644 --- a/Xamarin.Forms.Platform.WinRT/Xamarin.Forms.Platform.WinRT.csproj +++ b/Xamarin.Forms.Platform.WinRT/Xamarin.Forms.Platform.WinRT.csproj @@ -69,7 +69,10 @@ <Compile Include="PlatformConfigurationExtensions.cs" /> </ItemGroup> <ItemGroup Condition=" '$(OS)' != 'Unix' "> - <Compile Include="BrushHelpers.cs" /> + <Compile Include="BrushHelpers.cs" /> + <Compile Include="NativeBindingExtensions.cs" /> + <Compile Include="NativeEventWrapper.cs" /> + <Compile Include="NativePropertyListener.cs" /> <Compile Include="NativeViewWrapper.cs" /> <Compile Include="NativeViewWrapperRenderer.cs" /> <Compile Include="ViewExtensions.cs" /> |