I have a ListBox populated with data coming from XML.
Fine so far, the problem is that I get some errors when I try to tombstone it.
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
State["listbox1"] = listBox1.ItemsSource;
}
Then:
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
if (State.ContainsKey("listbox1"))
{
listBox1.ItemsSource = (IEnumerable)State["listbox1"];
}
}
When I hit the start button I already get an error. The App.xaml.cs opens and the line below becomes yellow
System.Diagnostics.Debugger.Break();
I've also used tombstoning helper but it did not return the items in my listbox.
What is the listbox bound to? And what error are you seeing?
If it's a DataServiceCollection, you may have tracking turned on & you cannot put it flatly in Isolated Storage or State dictionaries. Should be fine if using ObservableCollection.
Thanks!
Related
I quickly made a Windows Forms project which loads a GUI of different textboxes with float values. Some of them do have already a value initialized. All textboxes have to be updated after one of them is changed.
public Form1()
{
InitializeComponent();
initializeValues();
calculateValues();
}
public void initializeValues()
{
//textboxes are filled/initialized with default float values
}
public void calculateValues()
{
//here all textboxes are new calculated and updated
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
calculateValues();
}
private void textBox2_TextChanged(object sender, EventArgs e)
{
calculateValues();
}
Problem:
When I execute this project, it throws me a StackOverflowException which is unhandeled (infinite loop or infinite recursion). I think it's because during the calculateValues() method the text of the textBoxes will be changed and then the Eventhandlers are activated. That's the infinite loop :-(
How I have to change my code construct above to avoid this?
Thanks.
You should not using and calling "initializeValues();" (the cause of the infinite loop).
A first solution could be to put the init value of a TextBox in InitializeComponent :
MyTextBox.Text = myInitValue;
I solved the problem by changing the Event to "KeyPress". In this case, the Event is not activated by the method itself. No more infinite loops. Setting breakpoints and step through helped me to understand "the flow". Thanks CodeCaster.
I need to recreate new page instance on every page load (also when user pressed Back button).
So I overrided OnBackKeyPress method:
protected override void OnBackKeyPress(CancelEventArgs e)
{
base.OnBackKeyPress(e);
if (NavigationService.CanGoBack) {
e.Cancel = true;
var j = NavigationService.RemoveBackEntry();
NavigationService.Navigate(j.Source);
NavigationService.RemoveBackEntry();
}
}
The problem is that I can't handle case when user press back button to close CustomMessageBox dialog. How can I check it? Or is there any way to force recreation of page instance when going back through history state?
Why do you need to recreate the page instance? If you are simply trying to re-read the data to be displayed, why not put the data loading logic into OnNavigatedTo()?
Assuming that is what you are actually trying to achieve, try something like this...
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
// don't do your data loading here. This will only be called on page creation.
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
LoadData();
base.OnNavigatedTo(e);
}
MyViewModel model;
async void LoadData()
{
model = new MyViewModel();
await model.LoadDataAsync();
}
}
If you also have specific logic that you need to run on first construction of the page vs. on a back key navigation, check the NavigationMode property of the NavigationEventArgs object that gets passed to OnNavigatedTo.
if(e.NavigationMode == NavigationMode.New)
{
//do what you need to do specifically for a new page instance
}
if (e.NavigationMode == NavigationMode.Back)
{
// do anything specific for back navigation here.
}
Ha, in the near thread, i have opposite question :)
What about MessageBox - it depends, which one are you using. It can be custom message box, for example. Anyway, try to check MessageBox.IsOpened (or alternative for your MessageBox) in your OnBackKeyPress().
Another solution is to use OnNavigatedTo() of the page you want to be new each time.
Third solution: in case you works with Mvvm Light, add some unique id in ViewModel getter, like
public MyViewModel MyViewModel
{
get
{
return ServiceLocator.Current.GetInstance<MyViewModel>((++Uid).ToString());
}
}
This would force to recreate new ViewModel each time, so you'd have different instance of VM, so you would have another data on the View.
I have a list of items that goes to another page, That page is hooked up to a view model. In the constructor of this view model I have code that grabs data from the server for that particular item.
What I found is that when I hit the back button and choose another item fromt hat list and it goes to the other page the constructor does not get hit.
I think it is because the VM is now created and thinks it does not need a new one. I am wondering how do I force a cleanup so that a fresh one is always grabbed when I select from my list?
I faced the same issue, that's how i solved it.
Have a BaseView class, override OnNavigatedTo
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if (NavigatedToCommand != null && NavigatedToCommand.CanExecute(null))
NavigatedToCommand.Execute(null);
}
add DependencyProperty.
public static readonly DependencyProperty NavigatedToCommandProperty =
DependencyProperty.Register("NavigatedToCommand", typeof(ICommand), typeof(BaseView), null);
public ICommand NavigatedToCommand
{
get { return (ICommand)GetValue(NavigatedToCommandProperty); }
set { SetValue(NavigatedToCommandProperty, value); }
}
On the necessary pages, add to xaml (and, of course, inherit BaseView )
NavigatedToCommand="{Binding OnNavigatedToCommand}"
In the ViewModel, make command itself
public RelayCommand OnNavigatedToCommand
{ get { return new RelayCommand(OnNavigatedTo); } }
and implement method you want to call to update list
public async void OnNavigatedTo()
{
var result = await myDataService.UpdateMyList();
if (result.Status == OK)
MyList = result.List;
}
So, now, every time you navigate to page with list, inside of overriden OnNavigatedTo(), a NavigatedToCommand would be executed, which would execute OnNavigatedToCommand (which you set in xaml), which would call OnNavigatedTo, which would update your list.
A bit messy, but MVVM :)
EDIT: What about cleanings, they can be done in OnNavigatedFrom(), which works the same. Or OnNavigatingFrom(), which also can be useful in some cases.
I have a property and depending upon it's state (say A and B) I either show a usercontrol of animation or a image.
Now, if the property changes, I want to trigger the datatemplate selector again. On searching, I found that in WPF I could have used DataTemplate.Trigger but it's not available in WP.
So, my question is
Is their a way to trigger datatemplate selector so when property changes from state A to B, then appropriate usercontrol gets selected. If yes, then please give some example how to implement it.
Also, as there are only two states, if think I can use Converter to collapse the visibility. For basic if else situation, I will need to write two converters.( Can I somehow do it using one converter only?)
Here is the exact situation.
If state == A :
select userControl_A
else : select userControl_B
Also,
Will the animation usercontrol will effect the performance when it's in Collapsed state?
EDIT- Just realized, I can use parameter object to write just one converter.
You could implement a DataTemplateSelector like described here.
I use it and it works pretty well.
EDIT:
If you need to update the DataTemplate when the property changes, you should subscribe to the PropertyChanged event of the data object in the TemplateSelector and execute the SelectTemplate method again.
Here is the code sample:
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
City itemAux = item as City;
// Subscribe to the PropertyChanged event
itemAux.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(itemAux_PropertyChanged);
return GetTemplate(itemAux, container);
}
private DataTemplate GetTemplate(City itemAux, DependencyObject container)
{
if (itemAux != null)
{
if (itemAux.Country == "Brazil")
return BrazilTemplate;
if (itemAux.Country == "USA")
return UsaTemplate;
if (itemAux.Country == "England")
return EnglandTemplate;
}
return base.SelectTemplate(itemAux, container);
}
void itemAux_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
// A property has changed, we need to reevaluate the template
this.ContentTemplate = GetTemplate(sender as City, this);
}
I am setting selecteditem manually
public pageXXXX()
{
InitializeComponent();
this.cargaLista();
}
private void cargaLista()
{
this.lPickTipo.SelectedItem = this.lPickTipo.Items.OfType<tipos>().First(i => i.tipo == varString);
// here i load other data
//
}
Ok. Runs fine.
But my problem is that selectionchanged event is fire last, not when I set manually the SelectedItem
This is a problem for me. Because I run calc inside "SelectionChanged" event and I need to run calc when I selecteditem because other functions depend on this result
private void lPickTipo_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
try
{
if (this.lPickTipo.SelectedItem != null)
{
if (lPickTipo.SelectedIndex > -1)
{
this.calcularTotales();
}
}
}
catch (Exception EXC)
{ // CACTHING }
}
Why is fire last? How I can solve this?
In that you can't change the order that system level events are raised you'll need to change your logic to account for what the platform does.
As you haven't provided any information on what you're actually basing on the selection or why it requires page (presumably) level events to be fired after the selection is changed it's hard to be more specific.