How can I scroll to a newly-added HubSection? - c#

I'm using a Hub to allow the user to drill down through hierarchical data. The Hub scrolls horizontally, and each HubSection contains a ListView of various items.
When a user taps an item, I add a new HubSection to the right. I would like the Hub to scroll to bring the new HubSection fully into view.
Doing this doesn't work:
myHub.Sections.Add(myNewHubSection);
myHub.ScrollToSection(myNewHubSection);
Adding a delay means it does ultimately scroll to the right position, so I suppose the problem is that the new HubSection hasn't rendered yet:
myHub.Sections.Add(myNewHubSection);
await Task.Delay(1000);
myHub.ScrollToSection(myNewHubSection);
I also tried measuring the HubSections and animating manually as detailed here, but that fails too for the same reason - the new HubSection still has zero size when it's just been added.
Is there a nicer way to do this? Animated would be much preferable.

Can you subscribe to myNewHubSection.Loaded and trigger the myHub.ScrollToSection() there?

You could try to manually call "UpdateLayout()" prior to calling scroll to section. This may force it to render and be able to scroll.
For the animation piece, this blog article has a good walkthrough:
http://blogs.u2u.be/diederik/post/2015/02/23/An-animated-ScrollToSection-for-the-Universal-Hub-Control.aspx
Alternatively, if you can somehow know the offset, you can use the ScrollViewerExtensions from the WinRTXamlToolkit. It also provides extensions for the AwaitableUI library that could be used to wait for the new Hub Section to load.

Related

How do you programmatically create new controls inside a custom WPF Panel implementation?

I'm creating an OverflowPanel derived from the WPF Panel class. The intent is that it will fill with items in a single direction, and when there are too many items to display, excess items will be removed and replaced with another control to hold the overflow. Think of a website's breadcrumbs, or the address bar in Windows File Explorer. This is a .Net Core 3/C# 8 project.
I have a partially working solution: I've inherited from Panel and overridden MeasureOverride() and ArrangeOverride() to get the behavior I want. My problem now is getting a button or some other control to display in place of the items being removed.
My initial, naive approach was to just create a Button in code and try to Measure/Arrange it.
public class OverflowPanel : Panel
{
// First by itself, but I did also try to host this in a new UIElementCollection
private readonly Button _overflowButton = new Button();
public override Size MeasureOverride(Size availableSize)
{
...
_overflowButton.Measure(availableSize);
// Do stuff with _overflowButton.DerivedSize.
...
}
// Also attempted to draw int in ArrangeOverride()
}
This did give me non-zero result for the measurement. (I put some dummy content in the button.) My algorithm gives me space on the screen where the button should go, however, nothing gets rendered there.
I also confirmed that there wasn't simply a button being drawn with no visual style, by inspecting the Live Visual Tree in Visual Studio.
I tried to make a UIElementCollection and add the button to that to see if it would add it to the visual tree, but this also did not work.
Most Google/StackOverflow results I've seen suggest something along the lines of this.Children.Add(_overflowButton), but this does not work when hosted inside an ItemsControl, as it takes over managing the collection of objects and throws an exception if you attempt to mess with it.
After digging around in the code for Panel and UIElementCollection, I noticed that Panel lets you override
UIElementCollection CreateUIElementCollection(FrameworkElement logicalParent)
to use a derived implementation of UIElemenetCollection. I created a PinningUIElementCollection to trick WPF into rendering the extra element. It stores extra items and then slips them in whenever the iterator is accessed. It also does index mangling to access both the extra collection of items and the automatically generated one.
This actually worked. My button is now displayed (albeit without the correct styling, but that's a separate issue.)
However my issue with this approach is that it seems like a lot of work. It also seems error prone: I could easily miss when it tries to use a numerical index and forget to mangle it, causing unpredictable results.
Is there a simpler/more straightforward way, in my derived Panel implementation, to display an extra button or some other arbitrary control with only a few less hoops?

Xamarin Forms - attaching scrollview.Scrolled to a function

When I attach a scrollview to a function like this
textScroll.Scrolled += (sender, e) => { onScrolled(); };
Each time I scroll up or down, OnScrolled() is called multiple times. I know I can get the size of the content and compare it to the ScrollY value, obviously the ScrollY value changes each time, but as far as I can see I won't know when the last call happens (per user scroll).
I only want to call this once per scroll, failing that call it each time as is happening now, but only act when I know I'm on the last call.
Is this possible?
thanks
It is possible, but with a custom renderer for each platform.
On iOS: you will want to implement delegates for DecelerationEnded and WillEndDragging. The reason for also implementing DecelerationEnded is to allow for a fling by the user and waiting for the velocity to come to 0.
On Android it is a bit more complicated. Here is a native Android SO post I followed and translated into c# in a renderer. Works pretty well for me.
Android: Detect when ScrollView stops scrolling
After having both implemented, you can call to your Xamarin.Forms view in order to notify that the view has Stopped scrolling (i.e. final call)

Navigation within Page using Template10

I have problem how to implement sub-page navigation in UWP. The page is in RootFrame, which I can use on navigation. But i want to use something like this:
<Page>
<Grid>
<Frame x:Name="MyFrame"/>
</Grid>
</Page>
What I want is, use Navigate method of control MyFrame in ViewModel. I can call the method from code-behind, but I'm developing my app using MVVM. I'm not sure, if Template10 can work with sub-frames.
I appreciate any advice.
EDIT:
More details:
I have pivot control which is in page. the pivot has 2 tabs (pivotitems). The content of the pivotitem must be navigable. What I mean: I pivotitem 1, I need to have one Frame and use it for navigation in the pivotitem. My problem is, how to use or how to call the frame in pivotitem from ViewModel, especially I need to call Navigate method. Now I'm using Template10's navigation service and it's working with rootframe. I don't know, how to use it for other let's say sub-frames.
You can always do this.
var nav = Bootstrapper.NavigationServiceFactory(BackButton.Attach, ExistingContent.Exclude, this.Frame);
This will give you a navigation service for the frame in your page. You can then use session state, if you like.
Bootstapper.SessionState["MyNav"] = nav;
From here your view-model can access the service and navigate. You can repeat this for as many frames as you have. And you can then handle navigation in your view-model without consideration of "where" the frame is, just that your logic requires it to nav.
Does this make sense?
I don't know how you are going to trigger the navigation change so I'll assume it will start from a button click. I am also assuming the button's Command property is already bound to an ICommand in the viewmodel (the same concepts can be applied to different kinds of views).
All we have to do now is to make the ICommand implementation call our custom NavigationService to perform the content switch. This NavigationService class will be nothing but a simple proxy to the window global frame. Its main navigation method can be as simples as:
public void Switch()
{
var rootFrame = Window.Current.Content as Frame;
if ((rootFrame.Content as ParentPage) != null)
{
rootFrame.Navigate(typeof(ChildPage));
}
}
So you have tagged this with Template10 but it seems to be a more general question for UWP as a whole. I wonder if you have considered all of the inherent complexities with this approach - specifically related to suspension and resume. For each frame you have, you would need to save and restore navigation state, which isn't straight-forward when you have nested frames. Have you also considered how global navigation would work?
Template 10 does support the concept of multiple NavigationServices and, therefore, multiple frames, but only from the perspective of you can create them. Template10 does not inherently understand how such frames may be related to each other, so cannot perform automatic back propagation where you have something like:
FrameA[Main->Page1->Page1:Pivot1.FrameB[View1->View2->View3]]
Here we have two frames - FrameA and FrameB. FrameA has navigated from
Main to Page1. Page1 has a Pivot that hosts FrameB in PivotItem1 and
FrameB has navigated from View1 to View 2 and from View2 to View 3.
Global navigation (i.e. the shell back, etc.) would be automatically wired to FrameA, so you would need to intercept that action, and then handle you own navigation activity for FrameB.
Take a look at the BackButtonBehavior to see how it is possible to intercept the global back and then put in place your own action.
I don't know if you can do something like that..
One possible workaround is to use a Messenger that sends a message from your viewmodel to the view's code behind.. I'm not a fan of this solution though, because as I said before you have to use the page's code behind..

Manually trigger NavigationThemeTransition in Windows Phone WinRT/Universal app

In my application I use a ContentControl like this:
<ContentControl x:Name="Content">
<ContentControl.ContentTransitions>
<NavigationThemeTransition />
</ContentControl.ContentTransitions>
</ContentControl>
The problem is that the NavigationThemeTransition is not triggered when changing the Content property of the ContentControl. I think this is because it is only triggered in a Frame control when calling the Navigate() method.
I need this transition to be run when the Content of the ContentControl changes...
Is there a way to trigger the navigation-in and navigation-out animation manually?
Or is there some visual state to which the control can got to run the animation?
To achieve this You would be needed to have Custom Transition for the Control shown here custom transitions and for implementing Transition Effects in coding you can have Reference from here Using Page Transitions via Code
You could try to use a Frame control instead of a ContentControl. If that doesn't work - you'd need to create a custom control that has a Frame in its template and when its content change happens - it would navigate to a new page to display the new content.
I haven't seen a way to trigger the built-in transitions other than invoking an action that these transitions were created for. Personally - I would rather create my own transition than hack around to invoke the built-in one. You should be able to create one that looks exactly the same as the built-in one.

LongListSelector interaction breaks when a popup is open in WP8

To dynamically place some content on a page in a Windows Phone 8 project, we use a popup with a grid to host the content.
When this page contains a LongListSelector control, the Tap interaction to stop scrolling no longer works. Swiping up and down works as expected.
The issue can be reproduced very easily by starting with a new Databound app and adding this piece of code in the page constructor:
private Popup p;
p = new Popup();
Grid grid = new Grid();
grid.Width = Application.Current.Host.Content.ActualWidth;
grid.Height = Application.Current.Host.Content.ActualHeight;
p.Child = grid;
p.IsOpen = true;
Using this code you can make the LongListSelector scrolling but a Tap does no longer work to stop the scrolling.
Has anyone seen this issue and found a solution or might this be a known issue with the LongListSelector?
The invisible Grid that you're putting over the LongListSelector (actually the whole page) is capturing the tap event and because the popup is not part of the visual tree the event doesn't bubble as you're expecting.
The anomaly here is that you can actually interact with the LLS at all.
The real question here isn't why this happens but why you'd do this? Obviously your reproduction is very simple but it's to a point that makes no sense.
What are you ultimately trying to achieve?
There are almost certainly more appropriate alternative ways to achieve your end goal.

Categories