WPF Navigate to other page - c#

I want to just navigate between pages
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void RouteItems(object sender, RoutedEventArgs e)
{
NavigationService nav = NavigationService.GetNavigationService(this);
nav.Navigate(new ItemsPage());
}
}
GetNavigationService returns null
<Window x:Class="Special.MainWindow"
Name="Window"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Special"
mc:Ignorable="d"
Title="MainWindow" WindowState="Maximized">
<Button Content="Go" Click="RouteItems"/>
</Window>
I don't want to use other method (changing Content).
EDIT
this.NavigationService is undefined

You need to, first add a Frame to your Xaml:
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Frame x:Name="MainFrame"></Frame>
<Button Content="Go" Click="RouteItems" Grid.Row="1"/>
</Grid>
then after you add your xaml pages, use the MainFrame to navigate:
private void RouteItems(object sender, RoutedEventArgs e)
{
MainFrame.NavigationService.Navigate(new Uri("Page1.xaml", UriKind.RelativeOrAbsolute));
}

Related

How to reach and-, name own FrameworkElement from xaml

I have the following, working code:
<Window x:Class="GemTowerDefense.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:GemTowerDefense"
mc:Ignorable="d"
Title="Gem Tower Defense" Height="670" Width="800"
Loaded="Window_Loaded">
<Window.Resources>
<local:GameControl x:Key="MyGameControl"/>
</Window.Resources>
<Grid>
<Border Background="Gray" Height="600" Width="600" Margin="3,26,189,3">
<local:GameControl/>
</Border>
</Grid>
</Window>
Here you can see that I have the "local:GameControl" duplicated. This is because I only had the GameControl inside the "Grid" and the "Border". Everything worked fine, I implemented OnRender inside GameControl, it draws out everything I want it to.
My problem is, that I want this local:GameControl to interact with the MainWindow's buttons:
<Button Click="Life_Button_Click" Content="Buy 1 Life" HorizontalAlignment="Left" Margin="608,26,0,0" VerticalAlignment="Top" Width="170"/>
<Button Click="Upgrade_Button_Click" Content="Upgrade Chances" HorizontalAlignment="Left" Margin="608,51,0,0" VerticalAlignment="Top" Width="170"/>
<Button Click="Place_Button_Click" Content="Place Gems" HorizontalAlignment="Left" Margin="608,156,0,0" VerticalAlignment="Top" Width="170"/>
So I added this inside "Grid". But inside the Button Click Event Handlers, I don't know how to reach GameControl.
What I want to do is something like this:
public partial class MainWindow : Window
{
GameControl control { get; set; }
private void Life_Button_Click(object sender, RoutedEventArgs e)
{
control.BuyLife();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
control = Application.Current.MainWindow.Resources["MyGameControl"] as GameControl;
}
}
How can I achieve this to work?
This doesn't work obviously, because I cannot name GameControl with an x:Key, only if I add it as a resource, but then I dont know how to refer to it as a FrameworkElement in the xaml code.
Give the control an x:Name:
<Border Background="Gray" Height="600" Width="600" Margin="3,26,189,3">
<local:GameControl x:Name="control" />
</Border>
You can then access it in the code-behind:
private void Life_Button_Click(object sender, RoutedEventArgs e)
{
control.BuyLife();
}

Trying to get a StatusBar in app that could be accessible from various pages

I have implemented two pages with navigation. Here is how my MainWindow and two pages are declared.
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sb="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="9*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Frame x:Name="frame" Grid.Row="0" />
</Grid>
</Window>
Here is my Page1
<Page x:Class="WpfApplication1.Page1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Title="Page1">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="9*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="This is Page 1" FontSize="20" />
<Button Content="Next" Grid.Row="1" Click="Button_Click"/>
</Grid>
</Page>
Here is Page2
<Page x:Class="WpfApplication1.Page2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Title="Page2">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="9*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="This is Page 2" FontSize="20" />
<Button Content="Exit" Grid.Row="1"/>
</Grid>
</Page>
In the code behind of MainWindow constructor, I navigate to Page1.
public MainWindow()
{
InitializeComponent();
this.frame.Navigate(new Page1());
}
When I run the application, I get to see Page1. Life is good so far. I now need to bring a StatusBar where text will be updated from Page1 and Page2. I started with following interface.
public interface ISBView
{
void UpdateMessage(string message);
}
I then created a user control that implements this interface with following code.
<UserControl x:Class="WpfApplication1.MyStatusBar"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<StackPanel Orientation="Horizontal">
<TextBlock Name="statusMessage" />
</StackPanel>
</Grid>
</UserControl>
public partial class MyStatusBar : UserControl, ISBView
{
public MyStatusBar()
{
InitializeComponent();
}
public void UpdateMessage(string message)
{
this.statusMessage.Text = message;
}
}
I then used this user control in the MainWindow as follows.
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sb="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="9*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Frame x:Name="frame" Grid.Row="0" />
<StatusBar VerticalAlignment="Bottom" Grid.Row="1" >
<StatusBarItem>
<sb:MyStatusBar x:Name="myStatusBar" Content="Hi there!!!" />
</StatusBarItem>
</StatusBar>
</Grid>
</Window>
Now the constructor of MainWindow is changed to:
public MainWindow()
{
InitializeComponent();
this.frame.Navigate(new Page1(this.myStatusBar));
}
Whereas Page1 class looks like as follows.
public partial class Page1 : Page
{
private ISBView statusBar;
public Page1()
{
InitializeComponent();
}
public Page1(ISBView sb):base()
{
this.statusBar = sb;
sb.UpdateMessage("now on page1");
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.NavigationService.Navigate(new Page2());
}
}
Problem is now when I run application, Page1 is not shown at all. I just get a blank page without any error. Any idea what I am doing wrong here?
The problem is in the constructor of your Page. When you call your base constructor , the InitializeComponent() will not call and UI cannot render. So you should be calling 'this' constructor to execute both your logic and InitializationComponent().
public Page1(ISBView sb) : this()
{
this.statusBar = sb;
sb.UpdateMessage("now on page1");
}

Catch button click on user control

I have a window with a button and usercontrol. Now when I click on the button, the raised event, I wanna catch on usercontrol. I guess this principle it called event tunneling. But I don't know too, if this way would be the right way to catch the button click event.
Example
<Window x:Class="EventTunneling.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:uc="clr-namespace:EventTunneling"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Button Grid.Row="0" Content="Click me"></Button>
<uc:Control Grid.Row="1"></uc:Control>
</Grid>
</Window>
UserControl
<UserControl x:Class="EventTunneling.Control"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
</Grid>
</UserControl>
Now i want to catch the event on the partial class of usercontrol, that was raised from main window. How can i do that?
namespace EventTunneling
{
/// <summary>
/// Interaction logic for Control.xaml
/// </summary>
public partial class Control : UserControl
{
public Control()
{
InitializeComponent();
}
}
}
Unfortunately, you're doing this all wrong. First, you need to data bind your collection from the code behind to the DataGrid.ItemsSource property. Then, when the Button is clicked, just handle it in the code behind, where you have access to the collection and simply save it however you like:
In UserControl:
<DataGrid ItemsSource="{Binding Items}" ... />
In MainWindow:
<Button Grid.Row="0" Content="Click me" Click="Button_Click" />
In code behind (you should implement the INotifyPropertyChanged interface on this property):
public ObservableCollection<YourDataType> Items { get; set; }
...
private void Button_Click(object sender, RoutedEventArgs e)
{
SaveAsXml(Items);
}
In code behind constructor (or set it in any valid way you prefer):
DataContext = this;
Make a public event on the window.
Fire the event when the button is clicked.
Subscribe to the event from your control
you can simply do this when the button is clicked make a call to a public method in your user Control :
namespace EventTunneling
{
public partial class Control : UserControl
{
public Control()
{
InitializeComponent();
}
public void CatchEventOnUserControl()
{
//do your job here
//....
}
}
}
then when the button is clicked call the CatchEventOnUserControl method
<Window x:Class="EventTunneling.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:uc="clr-namespace:EventTunneling"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Button Grid.Row="0" Content="Click me" Click="Button_Click"></Button>
<uc:Control x:Name="mycontrol" Grid.Row="1"></uc:Control>
</Grid>
and the code behind is
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
mycontrol.CatchEventOnUserControl();
}
}

WindowsFormsHost ToolTipService

Simple case code for a problem I'm having:
<Window x:Class="WFHTooltipEnableTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
>
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<WindowsFormsHost Name="HostControl">
<wf:MaskedTextBox x:Name="mtbDate" Mask="00/00/0000"/>
</WindowsFormsHost>
<Button Content="Toggle" Grid.Row="1" Click="Button_Click"></Button>
</Grid>
</Window>
using System.Windows;
using System.Windows.Controls;
namespace WFHTooltipEnableTest
{
public partial class MainWindow : Window
{
bool enabled = true;
public MainWindow() {}
private void Button_Click(object sender, RoutedEventArgs e)
{
enabled = !enabled;
ToolTipService.SetIsEnabled(this.HostControl, enabled);
}
}
}
The button will toggle the value passed to SetIsEnabled. When false, the thing hosted in the windows forms host control gets disabled.
Can't seem to find any explanation for this behavior.

Content Element bound to property

I'm trying to have a window with a <Menu> element in it bound to a dependencyProperty:
Here is my Xaml:
<Window x:Class="attachement.xWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Menu/>
<ToolBarTray x:Name="ToolBarTray" Grid.Row="1">
</ToolBarTray>
<ScrollViewer Grid.Row="2">
</ScrollViewer>
</Grid>
</Window>
and here is my code behind:
public partial class xWindow : Window
{
public Menu Menu
{
get { return (Menu)GetValue(MenuProperty); }
set { SetValue(MenuProperty, value); }
}
public static readonly DependencyProperty MenuProperty = DependencyProperty.Register("Menu", typeof(Menu), typeof(xWindow), new UIPropertyMetadata(0));
public xWindow()
{
InitializeComponent();
}
}
now my question is: how can I bind the <Menu> element in my xaml to the dependency property in code behind so that when I do "myXwindow.Menu = new Menu(){...};" the menu is updated in the window?
thanks
NB: I tried setting the xaml like this : <Menu x:Name="Menu"> and remove the dp in c# so taht I could access directly the Menu defined in xaml, wich seems to work (no build or run error) but does not allow me to set it anew after the window has been displayed
You can wrap your Menu in some other control
<ContentControl x:Name="_menuContainer">
<Menu/>
</ContentControl>
And then write your property like this:
public Menu Menu
{
get { return (Menu)_menuContainer.Content; }
set { _menuContainer.Content = value; }
}

Categories