How to navigate to other page with button in WPF - c#

I have a second .xaml page set up under the name Page2.xaml and I want to make it so that when my button is clicked, the user is taken to Page2.xaml
I have this for my button inside of my Page1.xaml:
<Grid>
<Button x:Name="localModeBtn"
Style="{StaticResource MainButtonStyle}"
Content="local mode"
Click="localModeBtn_Click" />
</Grid>
And for the button event handler:
private void localModeBtn_Click(object sender, RoutedEventArgs e)
{
Uri uri = new Uri("Page2.xaml", UriKind.Relative);
this.NavigationService.Navigate(uri);
}
Upon clicking the button I receive an error that says "Cannot locate resource page2.xaml"
The thing is that Page2.xaml is in the same folder as Pag1.xaml so I can't see where I've gone wrong?

Solution to my own question:
I feel a bit silly providing a solution to my own question but thanks to Jasti's link I was able to sort my code out. As he had only posted a comment, I can't mark it as an answer, so here is the solution.
I changed the NavigationWindow to a Window and inserted:
<DockPanel>
<Frame x:Name="_NavigationFrame" NavigationUIVisibility="Hidden" />
</DockPanel>
And within the constructor of the MainWindow.xaml.cs I added:
_NavigationFrame.Navigate(new Page1());
Then the last step was to adjust the button event handler to:
this.NavigationService.Navigate(new Uri("Pages/Page2.xaml", UriKind.Relative));

You should use this, this worked for me:
var Page2= new Page2(); //create your new form.
Page2.Show(); //show the new form.
this.Close(); //only if you want to close the current form.
There is a variable type of a page with the page.xaml right name in your solution.
after that, you should use its methods to do it functionally.

Use any container and bind the content to any property in your viewmodel or codebehind.
After that you just have to update the property by setting a new page and call the PropertyChanged-event (see INotifyPropertyChanged interface). This will update the content of your container and you can display anything you want.

In case you want a separate window
NavigationWindow navWIN = new NavigationWindow();
navWIN.Content = new pageWFbchAdmin();
navWIN.Show();
//winBchAdmin.ShowDialog();

You don't need any C# code for this, just do it in XML:
<Button Content="local mode"
Command="NavigationCommands.GoToPage"
CommandParameter="/Page2.xaml"/>
(Reformatted code not tested)

private void Navigate_Click(object sender, RoutedEventArgs e)//By Prince Jain
{
this.NavigationService.Navigate(new Uri("Page3.xaml", UriKind.Relative));
}

My solution was adding a frame in the main window MainWindow.xaml
<Frame Name="Main" Content="" Margin="127,0,0,0" Background="#FFFFEDED" />
For navigation:
1- Navigating from the main windows on button click:
private void Button_Click(object sender, RoutedEventArgs e)
{
// navigate to pages/projects.xaml inside the main frame
Main.Content = new MyProject.Pages.Projects();
}
2- In case of navigation from the page inside a frame ex Projects.xaml
// declare a extension method in a static class (its your choice if you want to reuse)
// name the class PageExtensions (you can choose any name)
namespace MyProject
{
public static class PageExtensions
{
public static void NavigateTo(this Page page, string path)
{
Frame pageFrame = null;
DependencyObject currParent = VisualTreeHelper.GetParent(page);
while (currParent != null && pageFrame == null)
{
pageFrame = currParent as Frame;
currParent = VisualTreeHelper.GetParent(currParent);
}
if (pageFrame != null)
{
pageFrame.Source = new Uri(path, UriKind.Relative);
}
}
}
}
// to navigate from 'pages/projects.xaml' to another page
// heres how to call the extension on button click
this.NavigateTo("NewProject.xaml");
In addition, you can add another extension method that expects another Page object, in case you want to pass parameters to the constructor
// overloading NavigateTo
public static void NavigateTo(this Page page, Page anotherPage)
{
Frame pageFrame = null;
DependencyObject currParent = VisualTreeHelper.GetParent(page);
while (currParent != null && pageFrame == null)
{
pageFrame = currParent as Frame;
currParent = VisualTreeHelper.GetParent(currParent);
}
// Change the page of the frame.
if (pageFrame != null)
{
pageFrame.Navigate(anotherPage);
}
}
// usage
this.NavigateTo(new Pages.EditProject(id));

First of all, you'll need a frame in your window to hold the pages, so in my MainWindow.xaml I'll add a frame like this:
<Frame x:name="mainFrame"/>
Then We'll add an event listener to our navigation button in our MainWindow.xaml like this:
<Button
x:Name="navBtn"
Content="LIVE VIEW"
Click="NavBtn_Click">
</Button>
Now after we've set our window xaml up, we'll go to MainWindow.xaml.cs and write our code:
//this function should be automatically generated
private void NavBtn_Click(object sender, RoutedEventArgs e)
{
//we'll write this line, which opens our page
mainFrame.Content = new YourPage();
}
and that's it your navigation is ready!

In View (.xaml file):
<StackPanel>
<TextBlock>Outside area of frame</TextBlock>
<StackPanel Height="20" Width="400" VerticalAlignment="Top" Orientation="Horizontal">
<Button Content="Page 1" Width="200" Click="Button_Click"/>
<Button Content="Page 2" Width="200" Click="Button_Click_1"/>
</StackPanel>
<Frame Name="Main" Height="300" Width="700" Background="LightGray">
</Frame>
</StackPanel>
In code behind (.xaml.cs file):
private void Button_Click(object sender, RoutedEventArgs e)
{
Main.Content = new Page1();
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
Main.Content = new Page2();
}
Thesse two buttons will now help you to navigate between pages named Page1 and Page2. (Please take care of namespaces if the pages are present in folders or so).

Related

How do I access the child element of a Frame?

I have frames in my main window which are set to visible/collapsed based on user input:
<Grid>
<ScrollViewer x:Name="ScrollViewer1" Grid.Row="1" Grid.ColumnSpan="3" Margin="10,0,0,0" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<Frame Name="InputsFrame" Source="Inputs.xaml" NavigationUIVisibility="Hidden" Visibility="Visible"
ScrollViewer.CanContentScroll="True" />
</ScrollViewer>
<ScrollViewer x:Name="ScrollViewer2" Grid.Row="1" Grid.ColumnSpan="3" Margin="10,0,0,0" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" Visibility="Collapsed">
<Frame Name="LoadCasesFrame" Source="LoadCases.xaml" NavigationUIVisibility="Hidden" Visibility="Collapsed"
ScrollViewer.CanContentScroll="True" />
</ScrollViewer>
<!-- etc -->
</Grid>
The Inputs.xaml frame basically just consists of a 3rd party DoubleTextBox control (over 100 of them), and the user can just enter in values to that page. C# code behind:
private void InputsTab_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
LoadCasesFrame.Visibility = Visibility.Collapsed;
ScrollViewer2.Visibility = Visibility.Collapsed;
InputsFrame.Visibility = Visibility.Visible;
ScrollViewer1.Visibility = Visibility.Visible;
}
In this main window, there is a menu on top to allow for saving and opening the file. When I open the file, I want the data to be read (which I am able to do successfully) and also for the UI in the Inputs.xaml file to be updated.
The following code is in Inputs.xaml.cs:
public void LoadValues()
{
List<DoubleTextBox> dtb1 = App.GetLogicalChildCollection<DoubleTextBox>(inputsGrid);
for (int i = 0; i < dtb1.Count; i++)
{
foreach (var keyValuePair in App.globalDictionary)
{
var doubleTextBox = dtb1[i] as DoubleTextBox;
if (doubleTextBox.Name == keyValuePair.Key)
{
doubleTextBox.Value = 500;
break;
}
}
}
}
This function works (all the values in the GUI update to 500) when I call it from the Inputs.xml.cs page (for example, when I put it in the Page_Loaded event). However, I need to call this function from the MainWindow, since that is where the event handler for the Open File event is located:
private void openProject_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
if (openFileDialog.ShowDialog() == true)
{
string stringToDeserialize = File.ReadAllText(openFileDialog.FileName);
App.DeserializeJSONString(stringToDeserialize);
}
// call LoadValues here
}
Calling LoadValues() above doesn't update the GUI in the Input.xaml page. I originally had something like this in my MainWindow:
Inputs _inputs = new Inputs();
_inputs.LoadValues();
I know that the problem is that I have created a new object for Inputs and that's probably why it's not working. I'm unsure how to do it so that I don't use a new object -- wonder if I could use the InputsFrame somehow. I've also tried using event handlers to no success.
If you want to interact with the Inputs object that is in your Frame element, you need to retrieve that one, not create a new one.
You can do that like this:
((Inputs)InputsFrame.Content).LoadValues();
I.e. the Contents property of the Frame returns a reference to the Inputs object that is used to populate the Frame. Just cast that to Inputs to access the appropriate members of that class, such as LoadValues().

Hyperlinks in Xaml to navigate from one page to another

How can I create Hyperlinks in Xaml to navigate from one page to another page? I don't know actually how to use the hyperlink tags.
You can use RequestNavigate event to add a HyperLink class
Xaml:
<TextBlock>
<Hyperlink NavigateUri="http://www.google.com" RequestNavigate="Hyperlink_RequestNavigate">
Click here
</Hyperlink>
</TextBlock>
Code Behind:
private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e)
{
Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri));
e.Handled = true;
}
If you are looking for navigating to another page :
<StackPanel Grid.Row="1"
Margin="120,0,120,60">
<HyperlinkButton Content="Click to go to page 2" Click="HyperlinkButton_Click"/>
</StackPanel>
And handle it like :
private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
{
this.Frame.Navigate(typeof(BasicPage2));
}
And to move to external page : As mentioned by #Brainy

WPF C# Media Element Show first image of video

i have a .mov file that i want to play using MediaElement of WPF , i can play and pause with no worries as i use MediaState.Manual , but i want to show the first image or frame of the video when i load it , the source is set in code behind , i tried MediaElement.ScrubbingEnabled = true both code behind and xaml but it still doesn't show.
Here is my code ( xaml side ) :
<DockPanel Height="386" HorizontalAlignment="Center" Name="dockPanel1" VerticalAlignment="Top" Width="731">
<MediaElement Name="McMediaElement" LoadedBehavior="Manual" UnloadedBehavior="Manual" Stretch="Fill" MediaOpened="Element_MediaOpened" MediaEnded="Element_MediaEnded" OpacityMask="#FF040410" Height="386" IsVisibleChanged="SingAlong_IsVisibleChanged" ScrubbingEnabled="True"></MediaElement>
</DockPanel>
Code behind ( xaml.cs) :
private void PlayAudio()
{
McMediaElement.LoadedBehavior = MediaState.Manual;
McMediaElement.Source = new Uri("../../SingAlong/GrassHopper and Ants/ants2.mov", UriKind.RelativeOrAbsolute);
McMediaElement.ScrubbingEnabled = true;
McMediaElement.Play();
}
private void button1_Click_1(object sender, RoutedEventArgs e) // Play button
{
if (McMediaElement.Source != null)
{
McMediaElement.Play();
}
else
PlayAudio();
}
private void button2_Click(object sender, RoutedEventArgs e) // Pause button
{
McMediaElement.Pause();
}
From what I can gather, you are loading your video (setting the Source) only when you click button1, yet you want the first frame to show before this happens. To accomplish this, you will have to load your video in another method, preferably when your Page or Window loads. Then you can do the following:
McMediaElement.ScrubbingEnabled = true;
McMediaElement.Play();
McMediaElement.Pause();

GoBack button doesn't work if there's parameter passed in

I create a very simple project to test navigation. Below are the steps.
Create a Blank App (XAML/C#) project.
Add a Basic Page "PageTwo" to the project.
Add a HyperlinkButton and a TextBox to the MainPage.
In the code-behind of the MainPage, using Frame.Navigate method to navigate to PageTow and pass the TextBox's Text as the parameter.
Override OnNavigatedTo method of the PageTwo to get the passed parameter.
Run the project, input some text to the TextBox and click button to PageTwo, it works well, but if I click the built-in Back Button from PageTwo, I get an exception: Value cannot be null. If I comment the override OnNavigatedTo method, the Back button can lead me to the Main Page without exception.
Anyone can help?
MainPage.xaml:
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<StackPanel>
<TextBox Width="200" Name="TB"/>
<HyperlinkButton Content="Go to PageTwo" Click="HyperlinkButton_Click_1"/>
</StackPanel>
</Grid>
MainPage.xaml.cs:
private void HyperlinkButton_Click_1(object sender, RoutedEventArgs e)
{
Frame.Navigate(typeof(PageTwo), TB.Text);
}
PageTwo.xaml:
<TextBlock Name="TB" Grid.Row="1"/>
PageTwo.xaml.cs:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
TB.Text = e.Parameter as string;
}
In general when overriding any of the UI methods, you need to also call the base.
Your code does not cause an exception if I change the PageTwo.xaml.cs override of OnNavigatedTo to the following:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
TB.Text = e.Parameter as string;
// call base method
base.OnNavigatedTo(e);
}

Attached events in WPF: an OK button always requires 2 clicks to close

I have the following XAML
<Window x:Class="SimpleAttahEvent.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow">
<Grid>
<StackPanel Margin="5" Name="stackButton" ButtonBase.Click="DoSomething">
<Button Name="cmd1" Tag="The first button"> Command 1</Button>
<Button Name="cmd2" Tag="The second button"> Command 2</Button>
<Button Name="cmd3" Tag="The third button"> Command 3</Button>
</StackPanel>
</Grid>
</Window>
...With the following code to handle the attached events.
namespace SimpleAttahEvent
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
stackButton.AddHandler(Button.ClickEvent, new RoutedEventHandler(DoSomething));
}
private void DoSomething(object sender, RoutedEventArgs e)
{
Console.WriteLine(Button.ClickEvent.RoutingStrategy);
Console.WriteLine(TextBox.PreviewKeyDownEvent.RoutingStrategy);
if (e.Source == cmd1)
{
MessageBox.Show("First button is clicked");
}
if (e.Source == cmd2)
{
MessageBox.Show("Second button is clicked");
}
if (e.Source == cmd3)
{
MessageBox.Show("Third button is clicked");
}
}
}
}
These produce a dialog box with 3 buttons stacked vertically. When I click one of the button, a messagebox comes up with an OK button. However, the OK button on the dialogue box won't close unless I clicked it twice. Did I do this implicitly from the code given above?
Edit - Additional Info:
When I do this instead
private void DoSomething(object sender, RoutedEventArgs e)
{
object tag = ((FrameworkElement)sender).Tag;
MessageBox.Show((string)tag);
}
..it still require 2 clicks to close the message box.
Your problem is that you are doubling your handler. You do not have to click twice on the same OK; you are clicking on OK, which closes the first message. Then, the event is handled again and you get another exact same message that you have to click OK on. If you add + DateTime.Now to your messages you will see that this is indeed a second message
I missed this line on my first glance:
stackButton.AddHandler(Button.ClickEvent, new RoutedEventHandler(DoSomething));
Which is the same as the ButtonBase.Click from this line
<StackPanel Margin="5" Name="stackButton" ButtonBase.Click="DoSomething">
Choose one way to attach to event handlers and stick to it. Mixing them up is just going to cause confusion.

Categories

Resources