Navigating to specific ContentFrame when refreshing NavigationView - c#

I have an app which uses a NavigationView as a UI-control.
Now I have a SettingsPage where I can change the language of my UI between german and english.
I change the language with this code:
public static void German()
{
Log.Logger.Information("Language = German")
ApplicationLanguages.PrimaryLanguageOverride = "de-DE";
DataCollection.Current.LanguageChangedEvent.LanguageChanged();
}
The last line invokes an EventHandler which in turn invokes the following event on the MainPage.xaml.cs where the NavigationView is located.
public void ChangedLanguage(object source, EventHandlerBase e)
{
if (e.GetStatus())
{
Windows.ApplicationModel.Resources.Core.ResourceContext.GetForCurrentView().Reset();
Windows.ApplicationModel.Resources.Core.ResourceContext.GetForViewIndependentUse().Reset();
Frame.Navigate(this.GetType());
ContentFrame.Navigate(typeof(SettingsPage));
}
}
As it's possible to see I just want to return the user to the SettingsPage after changing the language.
But I always return back to the initial HomePage that I use when starting the app.
The code I use for the NavigationView is derived from the official NavigationView sample provided by Microsoft.
Is there any possible way to do this? The only possible thing I can imagine is to set a flag after the first page loading and then always check if that flag is set. But then I have the problem that I still could only land at the SettingsPage because I would have to make it the else destination for the flag-check.
Would really appreciate a more dynamic way if thats even possible :/
Greeting,
Daniel

The NavigationView sample just is a simple code sample for your reference. You need to make some changes by your requirements.
I just want to return the user to the SettingsPage after changing the language. But I always return back to the initial HomePage that I use when starting the app.
I've used the code on the document to make a code sample for testing. There're two places will cause your question.
First, in the NavView_Loaded event handler, it will always sets the home page as the selected item. But when you change the language, you re-navigate to 'MainPage' and make 'ContentFrame' navigate to 'SettingsPage'. At this time, the On_Navigated event handler will be first called. Then, the NavView_Loaded event handler will be called. That's the reason why your app always will return to home page.
Second, event if the NavigationView's SelectedItem has been set. But the NavigationView's ItemInvoked event will not be fired. So, what you see actually is not home page, it's a blank Frame control. You could use SelectionChanged event instead of ItemInvoked event. The SelectionChanged event will be fired when you set a new value for the NavigationView's SelectedItem. See the following sample:
private void NavView_SelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args)
{
if (args.IsSettingsSelected)
{
ContentFrame.Navigate(typeof(SettingsPage));
}
else
{
NavView_Navigate(args.SelectedItem as NavigationViewItem);
}
}
Then, let's back to your original question:
I can imagine is to set a flag after the first page loading and then always check if that flag is set. But then I have the problem that I still could only land at the SettingsPage because I would have to make it the else destination for the flag-check.
In my opinion, the flag will not affect you doing other things. You completely could define several flags. Please see my following code snippet for reference:
public static void German()
{
Log.Logger.Information("Language = German")
ApplicationLanguages.PrimaryLanguageOverride = "de-DE";
ApplicationData.Current.LocalSettings.Values["IsSwitchingLanguage"] = true;
DataCollection.Current.LanguageChangedEvent.LanguageChanged();
}
In your MainPage.xaml.cs:
public void ChangedLanguage(object source, EventHandlerBase e)
{
if (e.GetStatus())
{
Windows.ApplicationModel.Resources.Core.ResourceContext.GetForCurrentView().Reset();
Windows.ApplicationModel.Resources.Core.ResourceContext.GetForViewIndependentUse().Reset();
Frame.Navigate(this.GetType());
}
}
In NavView_Loaded event handler, I made some changes:
private void NavView_Loaded(object sender, RoutedEventArgs e)
{
......
foreach (NavigationViewItemBase item in NavView.MenuItems)
{
var IsSwitchingLanguage = ApplicationData.Current.LocalSettings.Values["IsSwitchingLanguage"];
if (IsSwitchingLanguage != null)
{
if ((bool)IsSwitchingLanguage)
{
NavView.SelectedItem = NavView.SettingsItem as NavigationViewItem;
ApplicationData.Current.LocalSettings.Values["IsSwitchingLanguage"] = false;
break;
}
}
if (item is NavigationViewItem && item.Tag.ToString() == "home")
{
NavView.SelectedItem = item;
break;
}
}
......
}

Related

How to make correct initialization of ComboBox?

I need show droppeddown combobox after start program.
I need in dropdown style only, not simple style.
This is simple fragment of my program:
private void Form1_Shown(object sender, EventArgs e)
{
CB1.Items.Add("1");
CB1.DropDownStyle = ComboBoxStyle.DropDown;
CB1.DroppedDown = true;
}
But I found the watch sign as cursor till I click on Form in any place.
I guessed that my Form have not fully active state and wait for something.
When I click Form (or combobox or any control) by LBM, it activated fully and all works fine.
Of course the combobox is dropup then, so I need click combobox twice.
Đ•ell me please what is correct initialization of such style combobox without "Cursor = Cursors.Default;"
You can simply wait until cursor is the default:
while (Cursor.Current != Cursors.Default)
{
Application.DoEvents();
}
CB1.Items.Add("1");
CB1.DropDownStyle = ComboBoxStyle.DropDown;
CB1.DroppedDown = true;
Application.DoEvents simply process messages from the window queue, so you can process message until you get that cursor is the default. In that moment, you can drop down your control without problem.
If you prefer, create a extension method for the Form:
public static class FormExtends
{
public static void WaitToDefaultCursor(this Form form)
{
while (Cursor.Current != Cursors.Default)
{
Application.DoEvents();
}
}
}
And use it:
this.WaitToDefaultCursor();
CB1.Items.Add("1");
CB1.DropDownStyle = ComboBoxStyle.DropDown;
CB1.DroppedDown = true;
NOTE: I use Cursor.Default but not to change the cursor. The form is processing messages and it's difficult to select a good moment to drop down the control.

Overriding the Back Button in Prism for Windows Phone 8.1 Runtime

I'm using the Prism MVVM library for WinRT in a Windows Phone 8.1 project. Is it possible to prevent back navigation via the phone's back button and handle the back button press in the ViewModel?
Concrete scenario:
The user can select one item (the "active" item) from a list of items - like a player in a game. That item is a reference for the rest of the app's functionality, e.g. database queries.
Selecting one item returns the user to the previous (main) page.
In the same list, the user can also delete an item that is no longer needed. It should be possible to delete all items.
Problem: If the user deletes the active item or the last item and then taps the back button, I end up having an invalid active item.
To prevent that, I'd like to cancel the back button navigation and prompt the user to select or create another active item, ideally from the ViewModel.
Update: I have now added an event handler to the App.xaml.cs based on how I understood Nate's comment below. This should override it application-wide:
private void HardwareButtons_BackPressed(object sender, BackPressedEventArgs e)
{
Frame currentFrame = Window.Current.Content as Frame;
if (currentFrame == null)
{
return;
}
if (currentFrame.Content is SelectionPage)
{
e.Handled = true;
}
else if (currentFrame.CanGoBack)
{
currentFrame.GoBack();
e.Handled = true;
}
}
and subscribing to the event in the constructor:
#if WINDOWS_PHONE_APP
HardwareButtons.BackPressed += HardwareButtons_BackPressed;
#endif
This seems to be handling the back button press just fine but it does not stop the existing navigation. So it goes back in any case and twice in the default case.
This is possible. Here is the solution (mostly inspired by this discussion):
Create an interface that allows view models to disable the back navigation:
public interface IRevertState
{
bool CanRevertState();
void RevertState();
}
In the view model implement the interface:
public class myViewModel : ViewModel, IRevertState {
public bool CanRevertState() {
return (...) //condition under which back navigation should be disabled
}
public void RevertState() {
(...) // optionally reset condition if required
}
In App.Xaml.cs handle the back navigation:
#if WINDOWS_PHONE_APP
protected override void OnHardwareButtonsBackPressed(object sender, BackPressedEventArgs e) {
var page = (Page)((Frame)Window.Current.Content).Content;
if (page.DataContext is IRevertState) {
var revertable = (IRevertState)page.DataContext;
if (revertable.CanRevertState()) {
revertable.RevertState();
e.Handled = true;
return;
}
}
base.OnHardwareButtonsBackPressed(sender, e);
}
#endif

Trying to select text in Textbox in Dialog when gaining Focus

I'm trying to select the whole text in a dialog but I'm not able to do so.
I have a class Participant which has a Property Firstname. When I set the participant in my dialog I'm calling a Focus-Method. However, when the dialog is open it's only in focus but not selected.
This is my Focus-Method:
public void FocusSurname()
{
SurnameBox.SelectAll();
SurnameBox.Focus();
Keyboard.Focus(SurnameBox);
}
In the dialog I'm setting my participant as follow:
Participant Participant
{
get { return _participant; }
set
{
_participant = value;
FocusSurname();
}
}
My dialog open sourcecode is pretty much:
public void ShowDialog(object owner)
{
Owner = owner as Window;
ShowDialog();
}
Why is the text not selected? :(
Even when I call FocursSurname in my ShowDialog-Method nothing is changing.
what you are trying to accomplish is view related code (in my opinion). The mvvm guidiance or pattern use (or at least my understanding of it) state that you want to use behaviors or attached properties for that. Means extending xaml functionality to plugin view related behaviors...
I found a stackoverflow question that relates to your topic. Check out if this might help... or try to derive from that solution...
Link:
Initial Focus and Select All behavior
HTH
Bind following event handler method to GotFocus event of the text box
private static void SelectText(object sender, RoutedEventArgs e)
{
var textBox = e.OriginalSource as TextBox;
Keyboard.Focus(textBox);
textBox.SelectAll();
}

How to force a certain Event sequence

I wrote a small control that creates a popup for my Win8 Phone application which does all the nasty things for me like rotation, proper placement etc.
The popup is opened in a Popup control but not on a new phone page.
To close the popup, my control hooks up to the "backKeyPressed" event of the underlying page.
This works like charm until the underlying page has its own implementation of BackKeyPressed event. In this case, the page event is triggered but not the popup control event.
If I would own the event, I could create my own stack to call the last added event first, but I do not own the event of the pages.
As far as I know, I am unable to unregister any previously attached event handler and reassign it once my control unsubscribes from the event.
I could have only one implementation for the BackKeyPressed event which then informs the popup control to close itself (if open), if nothing was open, do the Page specific implementation. But this would require code changes on all pages where I might want to use the popup. Even worse, if I have 5 possible popups, I would have to check all of them :-(
So I am looking for an option to handle this centrally.
What other options do I have to overcome this situation?
Normally you cannot change the order of fired events - they are executed in registered order, but it's not required by specifications - source.
But as Jon Skeet says here:
Summary: For all sane events, you can rely on the ordering. In theory, events can do what they like, but I've never seen an event which doesn't maintain the appropriate ordering.
it is fired in registered order and should be.
BUT for your purpose (I think) you can set an event to invoke your method where you would control the order. I think simple example can show this behaviour:
public partial class MainPage : PhoneApplicationPage
{
private List<EventHandler<CancelEventArgs>> listOfHandlers = new List<EventHandler<CancelEventArgs>>();
private void InvokingMethod(object sender, CancelEventArgs e)
{
for (int i = 0; i < listOfHandlers.Count; i++)
listOfHandlers[i](sender, e);
}
public event EventHandler<CancelEventArgs> myBackKeyEvent
{
add { listOfHandlers.Add(value); }
remove { listOfHandlers.Remove(value); }
}
public void AddToTop(EventHandler<CancelEventArgs> eventToAdd)
{
listOfHandlers.Insert(0, eventToAdd);
}
public MainPage()
{
InitializeComponent();
this.BackKeyPress += InvokingMethod;
myBackKeyEvent += (s, e) => { MessageBox.Show("Added first"); e.Cancel = true; };
AddToTop((s, e) => { MessageBox.Show("Added later"); });
}
}

Is there a BeforeUpdate for a C# ComboBox on a Winform

I come from the VBA world, and remember there was a BeforeUpdate call I could make on a combobox. Now I am in C# (and loving it) and I was wondering is there a BeforeUpdate call for a ComboBox on a Winform?
I can make an invisible textbox and store the info I need there and after the update, look at that box for what I need, but I was hoping there was a simplier solution.
One of the goodies of WF is that you can easily make your own. Add a new class to your project and paste the code below. Compile. Drop the new control from the top of the toolbox onto your form. Implement the BeforeUpdate event.
using System;
using System.ComponentModel;
using System.Windows.Forms;
public class MyComboBox : ComboBox {
public event CancelEventHandler BeforeUpdate;
public MyComboBox() {
this.DropDownStyle = ComboBoxStyle.DropDownList;
}
private bool mBusy;
private int mPrevIndex = -1;
protected virtual void OnBeforeUpdate(CancelEventArgs cea) {
if (BeforeUpdate != null) BeforeUpdate(this, cea);
}
protected override void OnSelectedIndexChanged(EventArgs e) {
if (mBusy) return;
mBusy = true;
try {
CancelEventArgs cea = new CancelEventArgs();
OnBeforeUpdate(cea);
if (cea.Cancel) {
// Restore previous index
this.SelectedIndex = mPrevIndex;
return;
}
mPrevIndex = this.SelectedIndex;
base.OnSelectedIndexChanged(e);
}
finally {
mBusy = false;
}
}
}
You may consider SelectionChangeCommited.
From MSDN:
SelectionChangeCommitted is raised
only when the user changes the combo
box selection. Do not use
SelectedIndexChanged or
SelectedValueChanged to capture user
changes, because those events are also
raised when the selection changes
programmatically.
This won't work when you have set your combobox to allow the user to type in the textbox though. Also, it won't tell you what the 'last' selected item was. You will have to cache this information. However, you don't need to store your information in a textbox. You can use a string.
You could try ValueMemberChanged, Validating, SelectedIndexChanged, or TextChanged. They don't fire like the BeforeUpdate, but you can look at what will be updated and handle the updated, or refuse it.
Out of the box, there's nothing like that. All of the events that deal with change in the combo box happen after the new value is already selected. At that point there's no way to tell what the value USED to be. You're best bet is what you eluded to. As soon as your ComboBox is populated save the SelectedItem to a temporary variable. Then, hook into the SelectedValueChanged event. At that point, your temporary variable will be your old value, and the SelectedItem will be your current value.
private object oldItem = new object();
private void button3_Click(object sender, EventArgs e)
{
DateTime date = DateTime.Now;
for (int i = 1; i <= 10; i++)
{
this.comboBox1.Items.Add(date.AddDays(i));
}
oldItem = this.comboBox1.SelectedItem;
}
private void comboBox1_SelectedValueChanged(object sender, EventArgs e)
{
//do what you need with the oldItem variable
if (oldItem != null)
{
MessageBox.Show(oldItem.ToString());
}
this.oldItem = this.comboBox1.SelectedItem;
}
I think what you wanted was the DropDown event. It will tell you what the value is before the user changes it. However, the user may end up not changing anything, so it's not exactly the same as BeforeUpdate.

Categories