I'm building an XAML app for Win 8 metro and ran into a "problem".
I have my mainpage.xaml with a button and in the mainpage.xaml.cs i have my constructor with initializecomponent(). when i click the button i call this function method:
private void GoToOtherPage()
{
this.Frame.Navigate(typeof(MySecondPage));
}
and works just fine.
However, in the contructor i also have a condition, and if true just carry on, but if it's false i want to run the GoToOtherPage() as well.
the constructor then looks somtehing like this
Public Mainpage()
{
InitializeComponent();
if(....)
{
//do some stuff
}
else
{
GoToOtherPage();
}
}
Since the initializecomponent() not is ready when this happens, i get the error Object reference not set to an instance of an object. which i (think) have found is refferring to this.Frame.
How should i do this the correct way? Put something like "WaitForThisFormToBeReady()" before the .Navigate or am i just on the complete wrong track here?
I think this.Frame becomes non-null after the page has been navigated to, so you could override OnNavigatedTo to handle it. Otherwise you can grab the Frame through (Frame)Window.Current.Content, a property on your App class or a NavigationService implementation - depending on how far you went with design patternizing your app.
Related
I have a page X in a Windows Store App (Windows 8.1) that gets shown after the splash screen. I want to evaluate something while / after the page loads, before the user can interact with the page.
Depending on the evaluation I want to do one of the two:
Just show the page X to the user and only navigate to page Y when the user clicks a button
Skip the current page and navigate to page Y automatically
1 works fine.
2 doesn't. I tried with calling this.Frame.Navigate(typeof(Y)) in the constructor, which didn't work because this.Frame was still null. Then I tried calling it in LoadState and OnNavigatedTo, but while in both cases this.Frame is not null, the Navigate() method returns false, which means the navigation fails. I tried to step into the method in Debugging, but it didn't work (?).
One hint is, that when hitting a breakpoint in the Navigate() code line when it gets called automatically, the screen still shows the splash screen, so it seems the UI elements have not been loaded yet. So the final question is: How can I do the evaulation and automatic navigation with all elements being loaded (or just so that it works)?
I don't see why you would call Frame.Navigate(...) in OnNavigatedFrom, but I can suggest two options that work for me:
Navigate to the second page in OnNavigatedTo: Although this doesn't work out of the box, it does when instructing the dispatcher to do the navigation:
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
this.Frame.Navigate(typeof(SecondPage));
});
}
}
An even easier solution is to do the navigation within the first page's Loaded event:
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
this.Loaded += (sender, args) =>
{
this.Frame.Navigate(typeof(SecondPage));
};
}
}
Of course, in both cases you can add whatever calculation you like within the lambda expression before calling Frame.Navigate(...)
EDIT: As a third alternative, maybe you should think about moving the calculation and decision part to OnLaunched in App.xaml.cs, and load either the first or the second page as root page, instead of opening the first page and immediately navigating on to the second?
This is really really the most annoying thing in my programming life:
I have a form which is kept alive along with my application. I have no code calling to some method which will dispose it, I don't want it to be disposed by any reason, and I'm sure if it happens, the reason would not be in my code. This form is a custom form which has a method called Next(), this Next() simply displays the next item info on the form.
The worst thing occurred when I pressed on a button which caused the call to Next() and there was an exception saying "Object reference not set to an instance of an object". What? And here is the code, I saved a reference of my form into a Form variable called "currentShownForm" (there is only 1 of my forms are shown at a time, all of these should live along with my application):
private void ShowForm(CustomRibbonForm form)
{
if (!form.Visible)
{
if (currentShownForm != null) currentShownForm.Hide();
form.Show();
currentShownForm = form;
}
}
and the Next() is called like this if I press the button Next:
currentShownForm.Next();
The enigma is in the form.Show();
With the method ShowForm() above, do you think the currentShowForm can be null??? What? Any case? The only moment it is null is before the first form is shown. After the first is shown, it will be the first form, any other next form is shown will be referred by it. So how it becomes null in some case??? The code in ShowForm() method is the only one can change the reference of currentShownForm in my project.
That really baffled me a lot, I couldn't believe in what I saw. Oh my God, I didn't have any clue on this, any idea, but I had to try the most ridiculous thing like this:
private void ShowForm(CustomRibbonForm form){
if (!form.Visible)
{
if (currentShownForm != null) currentShownForm.Hide();
currentShownForm = form;
form.Show();
}
}
Wow, before trying this, I didn't thing it could make any thing different, but it did work. The currentShownForm was not null when I pressed the Next button. What is the magic of the swap between the two lines of code in ShowForm??? I think of only 1 reason for that, the form.Show() somehow disposed the form itself? But why was it still shown?
The noticeable thing is my form is not .NET form (just inherits from .NET form), it is a custom form, and again it's from DotNetBar lib, wow, I have an idea about writing a book of the most annoying things you should know when working with DotNetBar (At least, I've had about 5 things to write, I bet there will be more if I still use it).
Please see the code above and give me some explanation on why it could happen that way? I can't explain it, in fact, I suppose that's a bug.
Your help would be highly appreciated!
Thank you!
UPDATE
Now, at least I know the original thing from which the problem occurs but still don't understand why:
In fact my form has some Custom controls, the involved control here is a CustomComboBox. This comboBox is a 2-in-1 control consisting of a normal ComboBox (again, a DotNetBar combobox namely ComboBoxEx) and a focusable Label (a custom UserControl). All the controls register a ParentChanged event to register some events for their parent form, like this:
protected override void OnParentChanged(EventArgs e){
if(Parent is CustomRibbonForm){
((CustomRibbonForm)Parent).RefreshControls += (s,ev) => {
Show();
Hide();
};
}
}
My form has a defined event called RefreshControls which will be raised when needed. It has a public method to raise that event called RefreshAllControls. And the call to that method is placed after ShowForm() in the Activated event handler for my main form (not the form I'm talking about) like this:
Activated += (s,e) => {
ShowForm(myForm);
myForm.RefreshAllControls();
};
And here is what next: When I comment out the Show(); and Hide(); in the OnParentChanged method, it works OK in both cases:
protected override void OnParentChanged(EventArgs e){
if(Parent is CustomRibbonForm){
((CustomRibbonForm)Parent).RefreshControls += (s,ev) => {
//Show();
//Hide();
};
}
}
But if not, only 1 case works (the currentShowForm is assigned before the call to form.Show(). It's closer to the cause to the problem but it's still not easy to understand.
Hope you have something to explain to me with this update! Thank you
Next UPDATE
Now I know the currentShownForm is null because the first assignment was in fact never done, the form is shown but the currentShownForm = form is not executed and because currentShownForm is initially null, it's still null after the call to ShowForm() method.
It's very close to the cause but it's still very strange:
private void ShowForm(CustomRibbonForm form){
if (!form.Visible)
{
if (currentShownForm != null) currentShownForm.Hide();
form.Show(); //<------ I marked a break point here.
currentShownForm = form; //<----- I also marked a break point here.
}
}
After marked two break points following each other in the same method, it seems to be sure that all the break points will be stepped through, but only the first is stepped through. After that, the main UI is shown and the second break point is bypassed???????? What?????????????? There are many of events occurred after the call to form.Show(), most of them are events in my Custom controls (relating to Focus, LostFocus and Paint events). This is the first time I've seen such a strange code stepping. Now this is very close to the cause, hope you have something to say. Thank you
I have an application for Windows 8 with a page (Frame) for displaying a list of items and a page for downloading & displaying the items details. I am also using MVVM Light for sending notifications.
Application use goes something like this:
Open Main Page
Navigate to List Page
Frame.Navigate(typeof(MyPage));
Choose Item
//Complete logic
Frame.GoBack();
Back on Main Page, I start downloading the file in the view model, I send ONE NotificationMessage saying BeginDownloadFile and after it is downloaded ONE NotificationMessage saying EndDownloadFile.
The first time I do steps 2,3, & 4 my NotificationReceived method is hit once, the second twice and so forth.
private async void NotificationMessageReceived(NotificationMessage msg)
{
if (msg.Notification == Notifications.BeginDownloadFile)
{
FileDownloadPopup.IsOpen = true;
}
else if (msg.Notification == Notifications.EndDownloadFile)
{
FileDownloadPopup.IsOpen = false;
}
}
Additional information: I only have one FileDownloadPopup, yet each time, an additional popup is shown each time the NotificationMessageReceived method is called.
My only conclusion is that between navigating forwards and backwards in my app, there are multiple MainPages being created and never closed. This results in many NotificationsMessageReceived methods just waiting for a notification to come their way so they can show their popup.
I have two questions:
1. Does this sound like normal behaviour for a Windows 8 app?
2. How can I close all instances of the MainPage or return to the previous instance without creating a new instance?
Please let me know if I have missed something important out before marking my question down.
This sounds normal to me. The default navigation behaviour in Windows 8 is to create a new page instance each time you navigate to a new page, regardless of whether this is forward or back navigation.
Try setting the NavigatinCacheMode on MainPage to Required. See the MSDN documentation for details of how page caching works.
It sounds like you are registering eventhandlers in the page and then not removing them. Each time you navigate to the page again the handler is being added again in addition to the one you previously added. Try to add your event handler in OnNavigatedTo, and make sure you unregister it in OnNavigatedFrom.
protected override void OnNavigatedTo(Windows.UI.Xaml.Navigation.NavigationEventArgs e)
{
MyEvent.OnDownloadRequest += MyLocalDOwnloadHandler; // add the handler
}
protected override void OnNavigatedFrom(Windows.UI.Xaml.Navigation.NavigationEventArgs e)
{
MyEvent.OnDownloadRequest -= MyLocalDOwnloadHandler; // remove the handler
}
I want to add an application bar to multiple pages of my app. So, I'm defining the application bar as an application resource so that it can be used by multiple pages. Now, the event handlers for these buttons are in the App class as mentioned here http://msdn.microsoft.com/en-us/library/hh394043%28v=VS.92%29.aspx.
But, these app bar buttons are basically shortcuts to important pages. So, clicking a button would just take you to the corresponding page. But, since I'm defining the event handlers in App.xaml.cs, it doesn't allow me to navigate. I understand the reason for this. But, I don't know how to solve the problem.
NavigationService.Navigate(new Uri("/Counting.xaml", UriKind.RelativeOrAbsolute));
says "An object reference is required for the non-static field, method or property System.Windows.Navigation.NavigationService.Navigate(System.Uri)"
Does it work if you get access to the frame?
(Application.Current.RootVisual as PhoneApplicationFrame).Navigate(new Uri("/Counting.xaml", UriKind.RelativeOrAbsolute));
Edit:
Each application has only one Frame. It's this frame that exposes the NavigationService. Therefore, the NavigationService is always accessible via the frame since there's always an instance of it in any Windows Phone app. Since you don't usually instantiate a new NavigationService, it's easy to think that it's a static method. However, it's actually a non-static class that gets instantiated automatically when your app is run. All you're doing in this case is getting the global instance, which is attached to the always-present Frame, and using that to navigate between pages. This means your class does not have to instantiate, or explicitly inherit, a NavigationService.
an other way to navigate to an other page from App.xaml.cs (using the app bar) is using the rootFrame var (at the end line):
private Frame rootFrame = null;
protected override async void OnLaunched(LaunchActivatedEventArgs args)
{
...
SettingsPane.GetForCurrentView().CommandsRequested += App_CommandRequested;
}
private void App_CommandRequested(SettingsPane sender, SettingsPaneCommandsRequestedEventArgs args)
{
SettingsCommand cmdSnir = new SettingsCommand("cmd_snir", "Snir's Page",
new Windows.UI.Popups.UICommandInvokedHandler(onSettingsCommand_Clicked));
args.Request.ApplicationCommands.Add(cmdSnir);
}
void onSettingsCommand_Clicked(Windows.UI.Popups.IUICommand command)
{
if (command.Id.ToString() == "cmd_snir")
rootFrame.Navigate(typeof(MainPage)); //, UriKind.RelativeOrAbsolute);
}
I found this approach a better one. The RootFrame object is already in the App.xaml.cs file, you just need to call it. Also putting this in a UI thread dispatcher is safer.
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
// change UI here
RootFrame.Navigate(new Uri("/MainPage.xaml", UriKind.Relative));
});
I would like to run some code onload of a form in WPF. Is it possible to do this? I am not able to find where to write code for form onload.
Judging by the responses below it seems like what I am asking is not something that is typically done in WPF? In Vb.Net winforms it is easy, you just go to the onload event and add the code that you need ran on load. For whatever reason, in C# WPF it seem very difficult or there is no standard way to do this. Can someone please tell me what is the best way to do this?
You can subscribe to the Window's Loaded event and do your work in the event handler:
public MyWindow()
{
Loaded += MyWindow_Loaded;
}
private void MyWindow_Loaded(object sender, RoutedEventArgs e)
{
// do work here
}
Alternatively, depending on your scenario, you may be able to do your work in OnInitialized instead. See the Loaded event docs for a discussion of the difference between the two.
Use the Loaded event of the Window. You can configure this in the XAML like below:
<Window x:Class="WpfTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Your App" Loaded="Window_Loaded">
Here is what the Window_Loaded event would look like:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// do stuff
}
This question was asked 4 years ago, but this answer may help others too so here goes -->
To do it simply and quickly - down and dirty, put the code you want to run in a method in the code-behind. then simply call the method before the MainWindow() InitializeComponent(). This poses dangers, but most times it works because the components are loaded before window initiation/display.
(This is working code from one of my projects.)
Let's say you want to play a short wave file when the app fires up. It would look like this;
using ...
using System.Windows.Media;
namespace yourNamespace_Name
{
/// sumary >
/// Interaction logic for MainWindow.xaml
/// /sumary>
public partial class MainWindow : System.Windows.Window
{
public MainWindow()
{
/*call your pre-written method w/ all the code you wish to
* run on project load. It is wise to set the method access
* modifier to 'private' so as to minimize security risks.*/
playTada();
InitializeComponent();
}
private void playTada()
{
var player = new System.Media.SoundPlayer();
player.Stream = Properties.Resources.tada;
// add the waveFile to resources, the easiest way is to copy the file to
// the desktop, resize the IDE window so the file is visible, right
// click the Project in the solution explorer & select properties, click
// the resources tab, & drag and drop the wave file into the resources
// window. Then just reference it in the method.
// for example: "player.Stream = Properties.Resources.tada;"
player.Play();
//add garbage collection before initialization of main window
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
}
Hope this helps those that are searching. :-)
Loaded event is raised after project is build. To do stuff before, you can ovveride OnStartup method in App.xaml.cs.
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
//...
base.OnStartup(e);
}
}