I have multiple pages in my WP7 app and I move in and out of apps by selections made during usage of the app. it is a data heavy app, but i'm not doing anything else but fill up the control by using its own ViewModel.
The ForwardIn transition animation fails to show up - which results in an ugly black screen pause for about 1.5 seconds and the page suddenly seems to popup. I have a white background in some pages so after appearing the phone tries to adjust the brightness automatically, which looks bad too. is there anythign specific I need to look out for?
Is there a way I can preload the page before navigation so that it happens smoothly, I'm using the performance progress bar in the previous pages to load data anyway. are there any ways to profile this page load so that I can check what took the most time.
I have seen this effect a lot when binding to lists. What I do is delay the binding until after the navigation/animation is complete. I usually show a progress bar after animation completes, wait about 50ms on a background thread to allow the progress bar to update it's UI and then bind to the list and hide the progress bar.
Here is the code I run when the animation completes:
progressBar.IsIndeterminate = true;
progressBar.Visibility = Visibility.Visible;
SynchronizationContext context = SynchronizationContext.Current;
Thread t = new Thread(() =>
{
/* Allow the UI to catch up */
Thread.Sleep(50);
context.Post((state) =>
{
list.ItemsSource = dataSource;
/* Hide the progress bar */
progressBar.IsIndeterminate = false;
progressBar.Visibility = Visibility.Collapsed;
}, null);
});
t.IsBackground = true;
t.Start();
Related
Summary
The Touch event is never raised with the ActionType of SKTouchAction.Moved, but SKTouchAction.Pressed is raised. Why does the .Moved event never get raised?
Detail
I am attempting to create a slider in SkiaSharp. This control will need to update the thumb (the little movable circle) when the user either touches on the slider or drags. This is hosted in a Xamarin Forms app, and I have created a SKCanvasView to draw the slider and to respond to touch events.
I have successfully responded to touch events, so I know the SKCanvasView is receiving some UI events, but the SKTouchAction.Moved is never raised.
Example Code
private SKCanvasView CreateSliderControl()
{
var control = new SKCanvasView();
control.PaintSurface += HandlePaintHeightControl;
control.EnableTouchEvents = true;
control.Touch += (sender, args) =>
{
var pt = args.Location;
switch (args.ActionType)
{
case SKTouchAction.Pressed:
// 1. This code gets hit whenever I touch the canvas
control.InvalidateSurface();
break;
case SKTouchAction.Moved:
// 2. This code never gets hit, even if I push, touch, slide, etc
control.InvalidateSurface();
break;
}
};
control.InputTransparent = false;
return control;
}
As shown above #1 gets hit (I can put a breakpoint there, and my control surface is invalidated). #2 never gets hit ever, but I expect it to get hit when I slide my finger over the control.
What I've Tried
Clean/rebuild to make sure my code actually was being deployed
Upgrade from SkiaSharp 1.60.3 to 1.68.0
All the crazy finger movements I could come up with
Read through https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/graphics/skiasharp/transforms/touch , but that uses XAML to assign an Effect (which I'm not familiar with) and I don't see a TouchEffect class available anywhere in my code to add it to the parent Grid that contains my SkiaCanvasView.
Found a similar issue on SkiaSharp's Github.
Try telling the OS that you want to "continue receiving touch events" by setting the Handled property in the event's args to true.
private SKCanvasView CreateSliderControl()
{
var control = new SKCanvasView();
control.PaintSurface += HandlePaintHeightControl;
control.EnableTouchEvents = true;
control.Touch += (sender, args) =>
{
var pt = args.Location;
switch (args.ActionType)
{
case SKTouchAction.Pressed:
control.InvalidateSurface();
break;
case SKTouchAction.Moved:
control.InvalidateSurface();
break;
}
// Let the OS know that we want to receive more touch events
args.Handled = true;
};
control.InputTransparent = false;
return control;
}
It's about TornadoFx' button.
If i use
button("push") {
action {
runAsyncWithProgress {
some()
}
}
}
I see progressindicator on the button.
How can I show/hide it programmatically?
The runAsyncWithProgress function automatically adds and removes the progress indicator so it only shows when the task is running.
The function saves the current graphic property of the node and displays a progress indicator in it's place. When the task is completed, the old graphic is reinstated. You can however modify the graphic property at any time, as long as you do it on the UI thread. Inside of your long running function you can do runLater { graphic = null } to remove the progress indicator for example.
I have above scenario: If user click on ListBox, it will either have sub items (again ListBox) or detail view.
So what i did currently is: Whenever user clicks any item, made a web call and filled up the same ListBox if clicked item is having further sub items.
Now, issue comes in picture:
Suppose i am in 4th screen (detail view),
Moved to the 3rd and 2nd screen with data maintained as stack (Its working fine, yes i am maintaining data in ObservableCollection<ObservableCollection<MyObjects>> so while moving back, i am fetching data from there)
Now, if i click any item in screen 2, it will open detail view for the screen 3 ListBox data.
Means that ListBox is not getting notified that we have filled data inside OnBackKeyPress()
FYI, i am filling up ListBox and WebBrowser in the same page., so my problem is that how do i notify ListBox once i filled up data from stack which i have maintained?
Yes i have also implemented INotifyPropertyChanged but don't know why its not working.
Please check my code:
ListBox and WebView screen: http://pastebin.com/K1G27Yji
RootPageItem class file with the implementation of INotifyPropertyChanged: http://pastebin.com/E0uqLtVG
sorry for pasting code in above way, i did as question is being long.
Problem:
How do i notify ListBox that data is changed from OnBackKeyPress?
And what is the behavior if you set:
listBox1.ItemsSource = null;
before
listBox1.ItemsSource = listRootPageItems;
This is just wrong architecture. Instead of reloading the same listbox, please add a single page for each screen. Share data between them inside the App class (internal static) and use the built in navigation stack for handling "going back". Don't override OnBackKeyPress for this purpose.
You will get your desired functionality for "free" with easier to maintain and use codebase.
Oops it was a silly mistake i made.
I forgot to set items[] array inside OnBackKeyPress() but was accessing while clicking item, hence its having items[] data of last step we moved in forward direction, it was executing the same data.
Now, i have just included a single line and it has solved my problem.
items = listRootPageItems.ToArray(); // resolution point
So final code of onBackKeyPress() is:
/**
* While moving back, taking data from stack and displayed inside the same ListBox
* */
protected override void OnBackKeyPress(CancelEventArgs e)
{
listBox1.Visibility = Visibility.Visible;
webBrowser1.Visibility = Visibility.Collapsed;
listBox1.SelectedIndex = -1;
if (dataStack.Count != 0)
{
listBox1.ItemsSource = null;
listRootPageItems = dataStack[dataStack.Count-1];
listBox1.ItemsSource = listRootPageItems;
items = listRootPageItems.ToArray(); // resolution point
dataStack.Remove(listRootPageItems);
e.Cancel = true;
}
}
I'm using popup to show my user control. I want to detect when the popup is REALLY shown up on the screen, then I show the progress bar, do some work, then hide the progress bar
MyDialog dialog = new MyDialog();
myPopup.Child = dialog;
myPopup.IsOpen = true;
dialog.progressLoading.Visibility = Visibility.Visible;
Thread.Sleep(3000)
dialog.progressLoading.Visibility = Visibility.Collapsed;
However, I realize that IsOpen = true doesnot show the popup instantly. The fact is that I must wait 3 seconds for it to show up.
How to know when popup shows up ?
I have an app in which I have a lot of references and the load time was not acceptable to me. I have removed the splash screen image and created an animated loading screen by having a separate project with no reference to the main application which then navigates to the first page of the rest of the app. It does start up fast now but it's a little lacking still.
I would like to do another animation right before the load screen goes away. The only way I can think of to do this is to actually preload the assemblies needed for the navigation to the next page, do an animation, and then navigate.
I have tried
OnNavigatedFrom but the animation doesn't have time to run since the page will be replaced by the new page very quickly from that point.
OnNavigatingFrom is no help either as it is called as soon as I call NavigationService.Navigate();
Searching the web and Stack Overflow :)
I also considered faking it a bit by having the next page show a duplicate of the load screen and do the last animation there, but it can't match the current state of the load screen animation and is harder to maintain
Thanks for any ideas!
If you want to force the loading of an assembly, just reference a type from this assembly.
For instance, something like Console.WriteLine(typeof(YourAssembly.SomeType)); will force the loading of YourAssembly.
Now for your problem, maybe you can use usercontrols? Put the content of your main page in a user control. Display the loading page, create the usercontrol in the background, let the animation play, then when the animation is done playing replace the page's content with the usercontrol.
It turns out that you can preload by just creating a new instance of the page you are going to navigate to. Unfortunately that has to be done on the UI thread which can cause animation slowdown, at least in my experience.
Here is a sample of how to do an animation, then preload, then do another animation before navigating. :
public partial class LoadScreen : PhoneApplicationPage
{
public LoadScreen()
{
InitializeComponent();
this.Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
var sb = new Storyboard();
// create your animation here
sb.Completed += (sender, args) => PreLoad();
sb.Begin();
}
private void PreLoad()
{
// this is the part that actually takes time and causes things to get loaded
// you may need it in a try/catch block depending on what is in your constructor
var page = new PageToNavigateTo();
// now create an animation at the end of which we navigate away
var sbOut = new Storyboard();
// create your animation here
sbOut.Completed += (sender, args) => NavigateToNextScreen();
sbOut.Begin();
}
private void NavigateToNextScreen()
{
// navigate here
}
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
// remove the loading screen from the backstack so the user doesn't see it again when hitting the back button
NavigationService.RemoveBackEntry();
}
}