Hide navigation bar but remember the history in wpf frame - wpf

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));
}

Related

Navigation in Silverlight 5

I want to navigate to new page on the click event of Next button. Suppose my current page is "FirstTestPage.xaml" and want to go on the page "SecondTestPage.xaml" on click on nextButton_Click Event
private void RadButton_Click(object sender, RoutedEventArgs e)
{
///CODE HERE
}
And also want the back button which transfer me to FirstTestPage.xaml.
Thank You
Please see my answer to the question: Making a Wizard in Silverlight + Xaml
to quote it: "I would suggest looking into the Silverlight Navigation Framework. It allows you to use "urls" to navigate between "pages" (which are your XAML user controls). It also also users to use the back and forth buttons in the browser, which may or may not be something you want to allow.
There is a VS 2010 template when you choose New Project, Silverlight, "Silverlight Navigation Application" that will help get you started."
You can also use a border or panel in the Xaml and change the content of that. Here's an example using border.
XAML
<Grid>
<Border x:Name="contentBorder" />
</Grid>
Code Behind:
private void RadButton_Click(object sender, RoutedEventArgs e)
{
this.contentBorder.Child = new SecondTestPage();
}
If you want to get fancy and have the Telerik controls (which I assume from your RadButton example) check out their transition control: http://demos.telerik.com/silverlight/#TransitionControl/FirstLook

WPF textbox binding disappears after navigating forward and back again

I have a WPF-application with a mainwindow and different pages. On one of the pages (OverzichtPage) I have a textBox bound to a DataController (Data). (which is a dependencyProperty on the codebehind of the page) (Might be worth mentioning: the DataController is a Singleton, so that patient is supposed to stay the same and can't disapear..)
public static DependencyProperty data = DependencyProperty.Register("Data", typeof(DataController), typeof(OverzichtPage));
public DataController Data
{
get { return (DataController)GetValue(data); }
set { SetValue(data, value); }
}
<TextBox Name="naamPatientTxtBox" Text="{Binding Path=Data.Patient.naam, Mode=TwoWay}" DataContext="{Binding ElementName=OP}" />
At first sight, this binding seems to work. When I navigate to another page by clicking a button
<Button Content="Meer info/ Wijzigen" Click="MeerInfoWijzigenBtn_Click" />
private void MeerInfoWijzigenBtn_Click(object sender, RoutedEventArgs e)
{
Uri pageFunctionUri = new Uri("View/ZorgTrajectPage1.xaml", UriKind.Relative);
NavigationService.Navigate(pageFunctionUri);
}
and navigate back, the binding suddenly stops working. I found out after the navigating back, the naamPatientTxtBox.GetBindingExpression(TextBox.TextProperty).ParentBinding; is empty. Does anyone have a clue why this binding suddenly disapears after the navigating? I really don't understand how this is possible.
Have you tried setting the KeepAlive property of the page to true?
You might be running into history/caching problems. State isn't autmatically kept.
I would put a breakpointat the Loaded event of the parent container (current Window or Page), check the DataContext property (does it contain anything?) and try to reset it if needed.
Another idea would be, set the TextBox.DataContext to Data, then the text to Patient.naam, in that way, it will be easier for you to debug it, also it will allow efficient DataContext inheritance.

WPF: Navigation/Design: How to keep track of state so I can change appearance of buttons?

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.

Can't set focus to a child of UserControl

I have a UserControl which contains a TextBox. When my main window loads I want to set the focus to this textbox so I added Focusable="True" GotFocus="UC_GotFocus" to the UserControls definition and FocusManager.FocusedElement="{Binding ElementName=login}" to my main windows definition. In the UC_GotFocus method i simply call .Focus() on the control i want to focus on but this doesn't work.
All i need to do is have a TextBox in a UserControl receive focus when the application starts.
Any help would be appreciated, thanks.
I recently fixed this problem for a login splash screen that is being displayed via a storyboard when the main window is first loaded.
I believe there were two keys to the fix. One was to make the containing element a focus scope. The other was to handle the Storyboard Completed event for the storyboard that was triggered by the window being loaded.
This storyboard makes the username and password canvas visible and then fades into being 100% opaque. The key is that the username control was not visible until the storyboard ran and therefore that control could not get keyboard focus until it was visible. What threw me off for awhile was that it had "focus" (i.e. focus was true, but as it turns out this was only logical focus) and I did not know that WPF had the concept of both logical and keyboard focus until reading Kent Boogaart's answer and looking at Microsoft's WPF link text
Once I did that the solution for my particular problem was straightforward:
1) Make the containing element a focus scope
<Canvas FocusManager.IsFocusScope="True" Visibility="Collapsed">
<TextBox x:Name="m_uxUsername" AcceptsTab="False" AcceptsReturn="False">
</TextBox>
</Canvas>
2) Attach a Completed Event Handler to the Storyboard
<Storyboard x:Key="Splash Screen" Completed="UserNamePassword_Storyboard_Completed">
...
</Storyboard>
and
3) Set my username TextBox to have the keyboard focus in the storyboard completed event handler.
void UserNamePassword_Storyboard_Completed(object sender, EventArgs e)
{
m_uxUsername.Focus();
}
Note that calling item.Focus() results in the call Keyboard.Focus(this), so you don't need to call this explicitly. See this question about the difference between Keyboard.Focus(item) and item.Focus.
Its stupid but it works:
Pop a thread that waits a while then comes back and sets the focus you want. It even works within the context of an element host.
private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
System.Threading.ThreadPool.QueueUserWorkItem(
(a) =>
{
System.Threading.Thread.Sleep(100);
someUiElementThatWantsFocus.Dispatcher.Invoke(
new Action(() =>
{
someUiElementThatWantsFocus.Focus();
}));
}
);
}
Just recently I had a list-box that housed some TextBlocks. I wanted to be able to double click on the text block and have it turn into a TextBox, then focus on it and select all the text so the user could just start typing the new name (Akin to Adobe Layers)
Anyway, I was doing this with an event and it just wasn't working. The magic bullet for me here was making sure that I set the event to handled. I figure it was setting focus, but as soon as the event went down the path it was switching the logical focus.
The moral of the story is, make sure you're marking the event as handled, that might be your issue.
“When setting initial focus at application startup, the element to
receive focus must be connected to a PresentationSource and the
element must have Focusable and IsVisible set to true. The recommended
place to set initial focus is in the Loaded event handler"
(MSDN)
Simply add a "Loaded" event handler in the constructor of your Window (or Control), and in that event handler call the Focus() method on the target control.
public MyWindow() {
InitializeComponent();
this.Loaded += new RoutedEventHandler(MyWindow_Loaded);
}
void MyWindow_Loaded(object sender, RoutedEventArgs e) {
textBox.Focus();
}
since i tried a fuzquat's solution and found it the most generic one, i thought i'd share a different version, since some complained about it looking messy. so here it is:
casted.Dispatcher.BeginInvoke(new Action<UIElement>(x =>
{
x.Focus();
}), DispatcherPriority.ApplicationIdle, casted);
no Thread.Sleep, no ThreadPool. Clean enough i hope.
UPDATE:
Since people seem to like pretty code:
public static class WpfExtensions
{
public static void BeginInvoke<T>(this T element, Action<T> action, DispatcherPriority priority = DispatcherPriority.ApplicationIdle) where T : UIElement
{
element.Dispatcher.BeginInvoke(priority, action);
}
}
now you can call it like this:
child.BeginInvoke(d => d.Focus());
WPF supports two different flavors of focus:
Keyboard focus
Logical focus
The FocusedElement property gets or sets logical focus within a focus scope. I suspect your TextBox does have logical focus, but its containing focus scope is not the active focus scope. Ergo, it does not have keyboard focus.
So the question is, do you have multiple focus scopes in your visual tree?
I found a good series of blog posts on WPF focus.
Part 1: It’s Basically Focus
Part 2: Changing WPF focus in code
Part 3: Shifting focus to the first available element in WPF
They are all good to read, but the 3rd part specifically deals with setting focus to a UI element in a UserControl.
Set your user control to Focusable="True" (XAML)
Handle the GotFocus event on your control and call yourTextBox.Focus()
Handle the Loaded event on your window and call yourControl.Focus()
I have a sample app running with this solution as I type. If this does not work for you, there must be something specific to your app or environment that causes the problem. In your original question, I think the binding is causing the problem.
I hope this helps.
After having a 'WPF Initial Focus Nightmare' and based on some answers on stack, the following proved for me to be the best solution.
First, add your App.xaml OnStartup() the followings:
EventManager.RegisterClassHandler(typeof(Window), Window.LoadedEvent,
new RoutedEventHandler(WindowLoaded));
Then add the 'WindowLoaded' event also in App.xaml :
void WindowLoaded(object sender, RoutedEventArgs e)
{
var window = e.Source as Window;
System.Threading.Thread.Sleep(100);
window.Dispatcher.Invoke(
new Action(() =>
{
window.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
}));
}
The threading issue must be use as WPF initial focus mostly fails due to some framework race conditions.
I found the following solution best as it is used globally for the whole app.
Hope it helps...
Oran
I converted fuzquat's answer to an extension method. I'm using this instead of Focus() where Focus() did not work.
using System;
using System.Threading;
using System.Windows;
namespace YourProject.Extensions
{
public static class UIElementExtension
{
public static void WaitAndFocus(this UIElement element, int ms = 100)
{
ThreadPool.QueueUserWorkItem(f =>
{
Thread.Sleep(ms);
element.Dispatcher.Invoke(new Action(() =>
{
element.Focus();
}));
});
}
}
}
I've noticed a focus issue specifically related to hosting WPF UserControls within ElementHosts which are contained within a Form that is set as an MDI child via the MdiParent property.
I'm not sure if this is the same issue others are experiencing but you dig into the details by following the link below.
Issue with setting focus within a WPF UserControl hosted within an ElementHost in a WindowsForms child MDI form
I don't like solutions with setting another tab scope for UserControl. In that case, you will have two different carets when navigating by keyboard: on the window and the another - inside user control. My solution is simply to redirect focus from user control to inner child control. Set user control focusable (because by default its false):
<UserControl ..... Focusable="True">
and override focus events handlers in code-behind:
protected override void OnGotFocus(RoutedEventArgs e)
{
base.OnGotFocus(e);
MyTextBox.Focus();
}
protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
{
base.OnGotKeyboardFocus(e);
Keyboard.Focus(MyTextBox);
}
What did the trick for me was the FocusManager.FocusedElement attribute. I first tried to set it on the UserControl, but it didn't work.
So I tried putting it on the UserControl's first child instead:
<UserControl x:Class="WpfApplication3.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid FocusManager.FocusedElement="{Binding ElementName=MyTextBox, Mode=OneWay}">
<TextBox x:Name="MyTextBox"/>
</Grid>
... and it worked! :)
I have user control - stack panel with two text boxes.The text boxes were added in contructor, not in the xaml. When i try to focus first text box, nothing happend.
The siggestion with Loaded event fix my problem. Just called control.Focus() in Loaded event and everthing.
Assuming you want to set focus for Username textbox, thus user can type in directly every time it shows up.
In Constructor of your control:
this.Loaded += (sender, e) => Keyboard.Focus(txtUsername);
After trying combinations of the suggestions above, I was able to reliably assign focus to a desired text box on a child UserControl with the following. Basically, give focus to the child control and have the child UserControl give focus to its TextBox. The TextBox's focus statement returned true by itself, however did not yield the desired result until the UserControl was given focus as well. I should also note that the UserControl was unable to request focus for itself and had to be given by the Window.
For brevity I left out registering the Loaded events on the Window and UserControl.
Window
private void OnWindowLoaded(object sender, RoutedEventArgs e)
{
ControlXYZ.Focus();
}
UserControl
private void OnControlLoaded(object sender, RoutedEventArgs e)
{
TextBoxXYZ.Focus();
}
I set it in the PageLoaded() or control loaded, but then I'm calling WCF async service and doing stuff that seems to lose the focus. I have to to set it at the end of all the stuff I do. That's fine and all, but sometimes I make changes to the code and then I forget that I'm also setting the cursor.
I had same problem with setting keyboard focus to canvas in WPF user control.
My solution
In XAML set element to Focusable="True"
In element_mousemove event create simple check:
if(!element.IsKeyBoardFocused)
element.Focus();
In my case it works fine.

Silverlight helix code-behind page navigation

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.

Resources