Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scrollview handler #1669

Merged
merged 19 commits into from
Jul 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/Controls/src/Core/HandlerImpl/ScrollView.Impl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ public partial class ScrollView : IScrollView
}
}

void IScrollView.RequestScrollTo(double horizontalOffset, double verticalOffset, bool instant)
{
var request = new ScrollToRequest(horizontalOffset, verticalOffset, instant);
Handler?.Invoke(nameof(IScrollView.RequestScrollTo), request);
}

void IScrollView.ScrollFinished() => SendScrollFinished();
}
}
}
2 changes: 1 addition & 1 deletion src/Controls/src/Core/HandlerImpl/VisualElement.Impl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ void IFrameworkElement.InvalidateMeasure()

// InvalidateMeasureOverride provides a way to allow subclasses (e.g., Layout) to override InvalidateMeasure even though
// the interface has to be explicitly implemented to avoid conflict with the VisualElement.InvalidateMeasure method
protected virtual void InvalidateMeasureOverride() => Handler?.UpdateValue(nameof(IFrameworkElement.InvalidateMeasure));
protected virtual void InvalidateMeasureOverride() => Handler?.Invoke(nameof(IFrameworkElement.InvalidateMeasure));

void IFrameworkElement.InvalidateArrange()
{
Expand Down
2 changes: 0 additions & 2 deletions src/Controls/src/Core/Hosting/AppHostBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@ public static partial class AppHostBuilderExtensions
{ typeof(Layout2.Layout), typeof(LayoutHandler) },
{ typeof(Picker), typeof(PickerHandler) },
{ typeof(ProgressBar), typeof(ProgressBarHandler) },
#if WINDOWS
{ typeof(ScrollView), typeof(ScrollViewHandler) },
#endif
{ typeof(SearchBar), typeof(SearchBarHandler) },
{ typeof(Slider), typeof(SliderHandler) },
{ typeof(Stepper), typeof(StepperHandler) },
Expand Down
4 changes: 2 additions & 2 deletions src/Controls/src/Core/Picker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,8 @@ void OnItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
// If the index has not changed, still need to change the selected item
if (newIndex == oldIndex)
UpdateSelectedItem(newIndex);
//This sends the notification to the Maui Handler to reload
OnPropertyChanged("Reload");

Handler?.Invoke("Reload");
}

static void OnItemsSourceChanged(BindableObject bindable, object oldValue, object newValue)
Expand Down
4 changes: 4 additions & 0 deletions src/Controls/src/Core/ScrollToRequestedEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,9 @@ object ITemplatedItemsListScrollToRequestedEventArgs.Item
}
}

public ScrollToRequest ToRequest()
{
return new ScrollToRequest(ScrollX, ScrollY, !ShouldAnimate);
}
}
}
8 changes: 6 additions & 2 deletions src/Controls/src/Core/ScrollView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ public View Content
if (_content != null)
InternalChildren.Add(_content);
OnPropertyChanged();

Handler?.UpdateValue(nameof(Content));
}
}

Expand Down Expand Up @@ -276,9 +278,9 @@ protected override SizeRequest OnSizeRequest(double widthConstraint, double heig

SizeRequest contentRequest;

if (Content is IFrameworkElement fe)
if (Content is IFrameworkElement fe && fe.Handler != null)
{
contentRequest = fe.Measure(widthConstraint, heightConstraint);
contentRequest = fe.Handler.GetDesiredSize(widthConstraint, heightConstraint);
}
else
{
Expand Down Expand Up @@ -361,6 +363,8 @@ void OnScrollToRequested(ScrollToRequestedEventArgs e)
{
CheckTaskCompletionSource();
ScrollToRequested?.Invoke(this, e);

Handler?.Invoke(nameof(IScrollView.RequestScrollTo), e.ToRequest());
}

protected override Size MeasureOverride(double widthConstraint, double heightConstraint)
Expand Down
22 changes: 0 additions & 22 deletions src/Core/src/ActionMapper.cs

This file was deleted.

104 changes: 104 additions & 0 deletions src/Core/src/CommandMapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
using System;
using System.Collections.Generic;
using Command = System.Action<Microsoft.Maui.IElementHandler, Microsoft.Maui.IElement, object?>;

namespace Microsoft.Maui
{
public abstract class CommandMapper
{
readonly Dictionary<string, Command> _mapper = new();

CommandMapper? _chained;

public CommandMapper()
{
}

public CommandMapper(CommandMapper chained)
{
Chained = chained;
}

private protected virtual void SetPropertyCore(string key, Command action)
{
_mapper[key] = action;
}

private protected virtual void InvokeCore(string key, IElementHandler viewHandler, IElement virtualView, object? args)
{
var action = GetCommandCore(key);
action?.Invoke(viewHandler, virtualView, args);
}

private protected virtual Command? GetCommandCore(string key)
{
if (_mapper.TryGetValue(key, out var action))
return action;
else if (Chained is not null)
return Chained.GetCommandCore(key);
else
return null;
}

internal void Invoke(IElementHandler viewHandler, IElement? virtualView, string property, object? args)
{
if (virtualView == null)
return;

InvokeCore(property, viewHandler, virtualView, args);
}

public CommandMapper? Chained
{
get => _chained;
set
{
_chained = value;
}
}
}

public class CommandMapper<TVirtualView, TViewHandler> : CommandMapper
where TVirtualView : IElement
where TViewHandler : IElementHandler
{
public CommandMapper()
{
}

public CommandMapper(CommandMapper chained)
: base(chained)
{
}

public Action<TViewHandler, TVirtualView, object?> this[string key]
{
get
{
var action = GetCommandCore(key) ?? throw new IndexOutOfRangeException($"Unable to find mapping for '{nameof(key)}'.");
return new Action<TViewHandler, TVirtualView, object?>((h, v, o) => action.Invoke(h, v, o));
}
set => Add(key, value);
}


public void Add(string key, Action<TViewHandler, TVirtualView> action) =>
Add(key, action);

public void Add(string key, Action<TViewHandler, TVirtualView, object?> action) =>
SetPropertyCore(key, (h, v, o) => action?.Invoke((TViewHandler)h, (TVirtualView)v, o));
}

public class CommandMapper<TVirtualView> : PropertyMapper<TVirtualView, IElementHandler>
where TVirtualView : IElement
{
public CommandMapper()
{
}

public CommandMapper(PropertyMapper chained)
: base(chained)
{
}
}
}
4 changes: 3 additions & 1 deletion src/Core/src/Core/IScrollView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace Microsoft.Maui
{
public interface IScrollView : IView
public interface IScrollView : IView
{
// TODO ezhart 2021-07-08 It might make sense for IPage and IScrollView to derive from (the not yet created) IContentView

Expand Down Expand Up @@ -46,5 +46,7 @@ public interface IScrollView : IView
/// Allows the native ScrollView to inform that cross-platform code that a scroll operation has completed.
/// </summary>
void ScrollFinished();

void RequestScrollTo(double horizontalOffset, double verticalOffset, bool instant);
}
}
12 changes: 11 additions & 1 deletion src/Core/src/Handlers/Element/ElementHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ public abstract partial class ElementHandler : IElementHandler
};

protected PropertyMapper _mapper;
protected CommandMapper? CommandMapper;
protected readonly PropertyMapper _defaultMapper;

protected ElementHandler(PropertyMapper mapper)
protected ElementHandler(PropertyMapper mapper, CommandMapper? commandMapper = null)
{
_ = mapper ?? throw new ArgumentNullException(nameof(mapper));
_defaultMapper = mapper;
_mapper = _defaultMapper;
CommandMapper = commandMapper;
}

public IMauiContext? MauiContext { get; private set; }
Expand Down Expand Up @@ -75,6 +77,14 @@ public virtual void UpdateValue(string property)
_mapper?.UpdateProperty(this, VirtualView, property);
}

public virtual void Invoke(string command, object? args)
{
if (VirtualView == null)
return;

CommandMapper?.Invoke(this, VirtualView, command, args);
}

private protected abstract object OnCreateNativeElement();

object CreateNativeElement() =>
Expand Down
2 changes: 2 additions & 0 deletions src/Core/src/Handlers/IElementHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ public interface IElementHandler

void UpdateValue(string property);

void Invoke(string command, object? args = null);

void DisconnectHandler();

object? NativeView { get; }
Expand Down
10 changes: 6 additions & 4 deletions src/Core/src/Handlers/Layout/LayoutHandler.iOS.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Linq;
using NativeView = UIKit.UIView;

namespace Microsoft.Maui.Handlers
Expand Down Expand Up @@ -34,9 +33,12 @@ public override void SetVirtualView(IView view)
NativeView.CrossPlatformMeasure = VirtualView.Measure;
NativeView.CrossPlatformArrange = VirtualView.Arrange;

//Cleanup the old view when reused
var oldChildren = NativeView.Subviews.ToList();
oldChildren.ForEach(x => x.RemoveFromSuperview());
// Remove any previous children
var oldChildren = NativeView.Subviews;
foreach (var child in oldChildren)
{
child.RemoveFromSuperview();
}

foreach (var child in VirtualView.Children)
{
Expand Down
14 changes: 9 additions & 5 deletions src/Core/src/Handlers/Page/PageHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,19 @@ public partial class PageHandler : IViewHandler
{
[nameof(IPage.Title)] = MapTitle,
[nameof(IPage.Content)] = MapContent,
};

#if __IOS__
Actions =
{
[nameof(IFrameworkElement.Frame)] = MapFrame,
}
#endif
public static CommandMapper<IPicker, PickerHandler> PageCommandMapper = new(ViewCommandMapper)
{
[nameof(IFrameworkElement.Frame)] = MapFrame,
};

public PageHandler() : base(PageMapper, PageCommandMapper)
#else
public PageHandler() : base(PageMapper)
#endif

{

}
Expand Down
2 changes: 1 addition & 1 deletion src/Core/src/Handlers/Page/PageHandler.iOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public static void MapContent(PageHandler handler, IPage page)

public static void MapFrame(PageHandler handler, IView view)
{
ViewHandler.MapFrame(handler, view);
ViewHandler.MapFrame(handler, view, null);

// TODO MAUI: Currently the background layer frame is tied to the layout system
// which needs to be investigated more
Expand Down
2 changes: 1 addition & 1 deletion src/Core/src/Handlers/Picker/PickerHandler.Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ void Reload()

NativeView.UpdatePicker(VirtualView);
}
public static void MapReload(PickerHandler handler, IPicker picker) => handler.Reload();
public static void MapReload(PickerHandler handler, IPicker picker, object? args) => handler.Reload();

public static void MapTitle(PickerHandler handler, IPicker picker)
{
Expand Down
2 changes: 1 addition & 1 deletion src/Core/src/Handlers/Picker/PickerHandler.Standard.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ public partial class PickerHandler : ViewHandler<IPicker, object>
{
protected override object CreateNativeView() => throw new NotImplementedException();

public static void MapReload(PickerHandler handler, IPicker picker) { }
public static void MapReload(PickerHandler handler, IPicker picker, object? args) { }
public static void MapTitle(PickerHandler handler, IPicker view) { }
public static void MapTitleColor(PickerHandler handler, IPicker view) { }
public static void MapSelectedIndex(PickerHandler handler, IPicker view) { }
Expand Down
5 changes: 2 additions & 3 deletions src/Core/src/Handlers/Picker/PickerHandler.Windows.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,8 @@ protected override void DisconnectHandler(MauiComboBox nativeView)
void SetupDefaults(MauiComboBox nativeView)
{
_defaultForeground = nativeView.Foreground;


}

void Reload()
{

Expand All @@ -42,7 +41,7 @@ void Reload()
NativeView.ItemsSource = new ItemDelegateList<string>(VirtualView);
}

public static void MapReload(PickerHandler handler, IPicker picker) => handler.Reload();
public static void MapReload(PickerHandler handler, IPicker picker, object? args) => handler.Reload();

public static void MapTitle(PickerHandler handler, IPicker picker)
{
Expand Down
13 changes: 7 additions & 6 deletions src/Core/src/Handlers/Picker/PickerHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
{
public partial class PickerHandler
{
public static PropertyMapper<IPicker, PickerHandler> PickerMapper = new PropertyMapper<IPicker, PickerHandler>(ViewHandler.ViewMapper)
public static PropertyMapper<IPicker, PickerHandler> PickerMapper = new(ViewMapper)
{
#if __ANDROID__
[nameof(IPicker.Background)] = MapBackground,
Expand All @@ -14,13 +14,14 @@ public partial class PickerHandler
[nameof(IPicker.Title)] = MapTitle,
[nameof(IPicker.TitleColor)] = MapTitleColor,
[nameof(IPicker.HorizontalTextAlignment)] = MapHorizontalTextAlignment,
Actions =
{
["Reload"] = MapReload,
}
};

public PickerHandler() : base(PickerMapper)
public static CommandMapper<IPicker, PickerHandler> PickerCommandMapper = new(ViewCommandMapper)
{
["Reload"] = MapReload
};

public PickerHandler() : base(PickerMapper, PickerCommandMapper)
{

}
Expand Down
Loading