I have WPF application and ListBoxItems as right Menu.
When specific ListBoxItem Islected i want to load different Window that i created called Home (instead of create several Grid elements and changed its Visibility) so i have this Grid:
<Grid>
<Frame Name="MyFrame"/>
</Grid>
And when the specific ListBoxItem Islected:
MyFrame.Content = new Home();
And got this error:
System.InvalidOperationException: ''MyApplication.Home' root element
is not valid for navigation.
'
Is this the right way to load other Window/Page ?
Home must be a Page or a UserControl. You can't set the Content property of a Frame to an instance of a Window.
If you want navigation history, you should consider using the NavigationService of the Frame to navigate to a page:
MyFrame.NavigationService.Navigate(new Uri("Home.xaml", UriKind.Relative));
Related
I have an ItemsControl displaying a list via binding. The list is of a ViewModel type which is then referenced in a DataTemplate to display a button. The button has it's UID bound to a GUID from the the view model. When a new view model is added to the bound list, I need to get hold of the button that will be added, as the buttons need to be able to be dragged/dropped by the user. At the moment the closest I can get is finding the ContentPresenter that displays the button, but the content of that ContentPresenter is of type view model.
Is there a way to find the button that has been added? Or should I not used a DataTemplate and create the buttons my self in order to access them?
I have used the VisualTree helper to get the content presenter, but have not managed to find the button.
You could handle the Loaded event for the Button:
<DataTemplate>
<Button Loaded="OnButtonLoaded" ... />
private void OnButtonLoaded(object sender, RoutedEventArgs e)
{
Button button = (Button)sender;
//...
}
You won't be able to get a reference to it using the VisualTreeHelper until it has actually been added to the visual tree and loaded anyway.
I have a frame on my main window. I have an ItemsControl in which I show the vertical menu from which user can select any Item and the page corresponding to specific Item is shown in the frame.
This works well.
When I set NavigationUIVisibility to Automatic:
1) Navigation Bar is displayed at the top.
2) If I enter some data in a textbox in page1 and then if I navigate away to page2.
Now again if I navigate to page1, the text in the textbox is there.
What I want is:
1) Hide the Navigation bar. For that I have set NavigationUIVisibility to Hidden.
This works good.
2) I want frame to remember history as I discussed in point 2 in above topic.
So, How to remember history when NavigationUIVisibility is set to hidden.
Or is there any other way to remember history when navigation bar is hidden.
You can re-style NavigationFrames and NavigationWindows so that they look completely different. In fact all of these images below are NavigationWindows, even the one without any navigation UI at all.
I put together an open source library for re-styling these at http://winchrome.codeplex.com so you can just steal the parts you need from the style. In fact if you just want a navigating panel with menu on the left, then its already covered in some of the demos for that project.
To answer your question as to why the TextBox clears it depends very much on what you are navigating to, and for some cases this is independent of the history.
Lets start simply, lets consider we have MyPage.xaml
<Page x:class="MyPage"...>
<TextBox/>
</Page>
If you are navigating to the same MyPage that you were before, then it will still have the same values in it.
If you are navigating to a new MyPage() then by default the TextBox will be empty.
If the navigation history is turned on, and you are navigating back, then you get the original MyPage and so see the same value in the TextBox.
Now lets consider if we are using MVVM style views bound to ViewModels.
In MyPage.xaml
<Page ...>
<TextBox Text="{Binding MyData}"/>
</Page>
In DataViewModel.cs
public class DataViewModel : INotifyPropertyChanged
{
private string myData;
public string MyData
{
get { return myData;}
set { ... }
//Normal implementation of INotifyPropertyChanged etc for MVVM
}
If you are navigating to a new Page() which is bound to the same ViewModel then both Pages will always be in sync and show the same data.
If navigating to the ViewModel and relying on DataTemplates to create a view, then you have still have two views but both sync from the same ViewModel.
If you use the history and navigate back, you get the original MyPage so see the original data again.
The Frame class has a property called BackStack which retains the back navigation history for a Frame. This property is available to you regardless of the NavigationUIVisibility setting.
Use PageFunction instead, which helps out you to navigate very backward retaining values for that pages..
Page1.xaml:
<PageFunction
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
x:Class="XYZ"
x:TypeArguments="sys:String"
Title="page1">
<TextBox x:Name="textbox"/>
<Button x:Name="button" Click="button_clicked"/>
</PageFunction>
private void button_clicked(object sender, RoutedEventArgs e)
{
Page2 page2 = new Page2();
page2.Return += page2_Return;
this.NavigationService.Navigate(page2);
}
void page2_Return(object sender, ReturnEventArgs<String> e)
{
OnReturn(new ReturnEventArgs<String>(null));
}
Page2.Xaml:
<PageFunction
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
x:Class="PQR"
x:TypeArguments="sys:String"
Title="page2">
...
</PageFunction>
void BackButton_Click(object sender, RoutedEventArgs e)
{
OnReturn(new ReturnEventArgs<String>(null));
}
I Have a user Control which Contains a ScrollPanel. And I want to bind the userControl's content property to the ScrollPanel.
So my xaml would look like:
<CustomControl>
<StackPanel/>
</CustomControl>
and in my UserControl my ScrollPanel child is set to StackPanel.
Do you mean ScrollViewer?
You have to remove the content from the user control (so the content no longer has a visual parent), then reassign the content to the scroll viewer.
In code:
var scrollViewer = new ScrollViewer();
var content = userControl.Content;
userControl.Content = null; // removes content from visual tree
scrollViewer.Content = content; // reassign content
If there's a way to do this via a binding, I haven't figured it out yet, though the situation where I'm having to do this is slightly different from yours.
I have an application that has a top level navigation menu which consists of series of buttons within a stackpanel. When a user clicks on a button the view model processes the command and updates the value of CurrentView (type UserControl). The CurrentView is bound to the element ContentControl as below.
<ContentControl Content="{Binding CurrentView}" />
I want the 'menu' to keep track of where the user is so that I can change the foreground of the navigation buttons, so users know where they are. What is the best way to do this? Should I wrap this 'menu' into a control?
Some of the views passed to the ContentControl will have their own sub menus. These submenus work in the same way, and I would like to change the foreground and background for these.
Most of what you are talking about here is typically done by using a Frame, and Navigation with Pages of content. Is there a specific reason you are not using this?
For Example:
<sdk:Frame x:Name="CenterFrame" BorderThickness="0" Source="/Home">
<sdk:Frame.UriMapper>
<sdk:UriMapper>
<sdk:UriMapping Uri="/Job/{ID}" MappedUri="/Views/JobView.xaml?ID={ID}"/>
<sdk:UriMapping Uri="/Home" MappedUri="/Views/HomeView.xaml"/>
<sdk:UriMapping Uri="/Resource/{ResourceName}" MappedUri="/Views/ResourceView.xaml?Resource={ResourceName}"/>
<sdk:UriMapping Uri="/Tasks" MappedUri="/Views/TaskView.xaml"/>
</sdk:UriMapper>
</sdk:Frame.UriMapper>
And then within your page:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (this.NavigationContext.QueryString.ContainsKey("Resource"))
{
ResourceViewModel rvm = ViewModelLocator.ResourceVMStatic;
if (rvm != null)
rvm.ResourceName = this.NavigationContext.QueryString["Resource"];
}
base.OnNavigatedTo(e);
}
If you don't want to use pages, and want to use controls, you can do that, but you will have to provide the tracking manually. I would recommend using a view model just for your navigation, which can persist some data itself.
I am new to silverlight and from what I gathered there isnt any direct functionality as regards to paging so I downloaded the helix project from here . I found it rather usefull but failed to find a way(using helix) to navigate the pages through code-behind . The reason why I need this is that I want to navigate to another page if a method executed successfully.
In the OnLoaded event of RootPage.xaml.cs you can see the following code:
this.rootFrame.Navigate( new Uri( "Page1.xaml", UriKind.Relative ) );
This programatically navigates to Page1.xaml (which implements NavigationPage) when the RootPage loads by calling the Navigate method of an instance of the Frame control defined in RootPage.xaml:
<h:Frame x:Name="rootFrame" Grid.Row="0" Grid.Column="1"
NavigationUIVisibility="Visible" Margin="4" />
This Navigate method in turn calls the Navigate method of the Frame's encapsulated StackJournal instance.
If you are in the code-behind of a page that does not have access to the parent Frame directly (i.e. any page other than RootPage) such as Page1.xaml you need to raise a RequestNavigate event that will bubble up to the nearest parent Frame.
The following code shows how to navigate programatically from a button click on Page1.xaml directly to Page3.xaml:
private void TestButton_Click(object sender, RoutedEventArgs e)
{
this.RaiseEvent(NavigationLink.RequestNavigateEvent,
new RequestNavigateEventArgs(new Uri("Page3.xaml", UriKind.Relative),
"rootFrame"));
}
Notice the targetName is "rootFrame", the parent Frame object that eventually performs the navigation.