I have an MvvmCross MvxSpinner binding in Android. The user selects a value and that gets reflected in my property MealTypeSelected.
<MvxSpinner
android:layout_width="match_parent"
android:layout_height="wrap_content"
local:MvxBind="ItemsSource MealTypeList;SelectedItem MealTypeSelected, Mode=TwoWay" />
The spinner is to allow the user to select the meal type (breakfast, lunch, dinner, etc). The meal type is represented by an Enum called MealType.
public enum MealType {Unspecified, Breakfast, Lunch, Dinner, Snack};
I want to make it easier on the user by initializing the spinner to a value based on the time of day when the ViewModel is shown. So if the page is loaded at noon, I'll guess that the selection should be "Lunch" for example.
The problem is, I have tried setting the MealTypeSelected property in the ViewModel at different locations of the life cycle: constructor, Init, and Start. But regardless of what I do, when the View loads, it changes the selection back to the default value of the Enum, which is the value "Unspecified".
Is there a way around this behavior and have the MvxSpinner initialized to specific value?
Try to add this to your "Setup.cs" file. I had the same struggle, and this worked for me. Cant remember where i found the solution the first time.
protected override void FillTargetFactories(IMvxTargetBindingFactoryRegistry registry)
{
MvxAppCompatSetupHelper.FillTargetFactories(registry);
base.FillTargetFactories(registry);
}
I had a similar problem when binding the SelectedItem of an MvxSpinner to my ViewModel, while also setting it in the ViewModel.
Overriding the Equals of the type that I was binding to fixed this problem.
public override bool Equals(object obj)
{
return this.Id == (obj as MyType)?.Id;
}
Since you seem to be binding directly to an enum, you might have to try and wrap it in another object.
Stack Overflow won't let me accept pnavk's comment as an answer but it is what I ended up doing. Each time the user selected something, I would change the first item to the list to what was selected. An ugly solution but it worked. If that's not acceptable to others, it looks like you might have to do some custom binding.
Related
How can i move
protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
to the viewmodel and still be able to control "back'ing"? In the codebehind, i can use e.Cancel = true;, but how to use it in the viewmodel?
You can't bind something that isn't bindable per say. All you can do is either create a fake binding using a Behavior<T>, but not much point in that.
Instead you could just simply forward the event in the ViewModel, doing something like:
e.OnCancel = ViewModel.OnBackKeyPress();
And then have OnBackKeyPress() return a bool.
The very first idea that i got - is to leave it in codebehind, and send message to viewmodel, so it should shange its state. But i'd still prefer to bind event to VM.
I am using this code to map a database to my Windows Phone 7 application.
In particular when I add a new Card item (in a Phone Page different from the home page) and when I get back to the home page the balance value of my Credit Card list does not update (Which is bound to an observable collection of type Card). I think I have added all the necessary NotifyPropertyChanged.
Am I missing something:
Code: Here
This is kind of a shot in the dark, but I don't see PropertyChanged being set anywhere... if PropertyChanged does not get set, then it will equal null and none of the NotifyPropertyChanged calls will actually call PropertyChanged().
I had a problem once that wouldnt update my URI, just try to actualize when you can, not sure how to go about your particular problem but I had a problem that when I changed teams in my app, the main page wouldnt update the statistics when you returned to it, so I just added a method that retrieves the value once more, I use nested classes with setters and getters so its all handled for me
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
method();
base.OnNavigatedTo(e);
}
I have an observableCollection bound to a pivot control in my UI. When I try to update the collection (clear() items and recreate) everything works fine unless the selectedIndex of the pivot control is bigger or equal to 2.
In that case I get an ArgumentOutOfRange exception when I try to call Add() to the observable collection. It is very strange.
I tried creating a new observable collection and then Add() items there, this seems to work but I doesn't refresh the UI unless I call my update function twice.
What can be wrong? Is this a bug?
This is a known issue.
Unhandled Exception When Setting Pivot Control SelectedItem/SelectedIndex Property to 3rd Pivot Item (WP7)
Not deferring navigation/(binding?) to the loaded event is a workaround.
You have probably alreade solved it but here is what I did.
As mentioned before this is a known "bug"/limitation.
You can however set the SelectedIndex in the Loaded event for the page.
See here:
http://christian-helle.blogspot.com/2011/02/working-around-pivot-selectedindex.html
This helped me and it works just fine now =)
To try and save load and performacne overhead, the framework only loads the currently displayed pivot and the ones either side. The other items are delay loaded when the neighbouring item is displayed. As a consequence of this you can experience issues when trying to set the SelectedItem to an item which hasn't been loaded or the page hasn't finished loading fully.
If you can share some code to demonstrate what you're trying to do we may be able to provide some more specific help.
As mentioned. The Pivot control is optimised to not load all the panels. If you are trying what I think you're trying, then I would suggest you switch to a Panorama Control which initalises all the PanoramaItems.
I'm going to try the fix suggested #Jimmy Engtröm. However, I've also been able to work around this by waiting until the Load has occurred.
<controls:Pivot x:Name="pivotCtrl" Title="{Binding ApplicationTitle}"
Loaded="OnPivotControlLoaded" Opacity="1">
And in the page's code behind:
private void OnPivotControlLoaded(object sender, RoutedEventArgs e)
{
// Restore the Pivot control's SelectedIndex
if (State.ContainsKey(SelectedPivotIndexKey))
{
pivotCtrl.SelectedIndex = State.Get<int>(SelectedPivotIndexKey);
}
myStoryboard.Begin();
}
Now, why the Storyboard? Well, when you wait until Load, you will see the first pivot and that's lame. So the Storyboard does a quick fade-in...just enough to disguise the fix. I tried just setting Visibility, but that would crash the app. Also note that, for design purposes, I leave Opacity set to 1 in the pivot control's XAML. Here's the Storyboard:
<Storyboard x:Name="myStoryboard">
<DoubleAnimation
Storyboard.TargetName="pivotCtrl"
Storyboard.TargetProperty="Opacity"
From="0.0" To="1.0" Duration="0:0:01"
/>
</Storyboard>
Here are the helper functions (placed in a separate class file and referenced, e.g. using MyApp.Helpers and the class file needs to reference System.Collections.Generic)
public static T Get<T>(this IDictionary<string, object> dictionary, string key)
{
return (T)dictionary[key];
}
public static void AddOrReplace<T>(this IDictionary<string, T> dictionary, string key, T item)
{
if (dictionary.ContainsKey(key))
dictionary.Remove(key);
dictionary.Add(key, item);
}
Again, it's not the greatest fix but it works alright and the fade-in is actually something I might employ elsewhere.
In my little cocoa application I have bound the properties of a class to some text fields with help of a NSObjectController. The only problem I have so far: you always have to leave a text field before the NSObjectController updates the class with the current input.
This becomes a problem if the user doesn't leave a texfield and clicks on a Save/Submit Button right away. The class doesn't contain the current input. Always a bad thing.
I am looking for a way to avoid this. Like telling the NSObjectController to get the current input even if the user had exited the field. If this is possible I could put this command in the save-Method before saving and all would be fine.
Send a commitEditing message to your controller in the handler for the OK button. This will do what you're asking for. It's as simple as:
- (void)save:sender {
if (![self.myObjectController commitEditing]) {
// Handle error when object controller can't commit editing
}
// Other stuff
}
If you go to the text field's value binding and check the "Continuously Updates Value" option, that will cause the new value to be set on the model object each time the user changes it, i.e. once for each keystroke. That would ensure that the model had the correct value before closing the window, though it may be a bit overkill, depending on what the effects (if any) are of the value being set in your data model.
In my winforms app, I have a UserControl that contains a DataGridView. I instantiate and load this UserControl when needed into a panel in my Main Form (frmMain). My problem is figuring out how to resond to or listen for events raised in my UC's DataGridView. For example, I want to handle the CellDoubleClick event of the DataGridView in my Main Form rather than through the UC.
Is this possible? I had thought of updating a property when the cell in the grid is double-clicked, and then let my Main form do whatever when that property changes - therefore I thought of using INotifyPropertyChanged. Im not heavily clued up on how to use it in m scenario however, and would deeply appreciate some help in this regard, or if anyone can suggest an alternate solution.
Much thanx!
Your user control must encapsulate some logic, so if you want to handle event of the DataGridView that is in your control the way you've described, you probably missing something in idea of user controls and encapsulation. Technically here two ways to do this:
Make a public property in your user control of type DataGridView.
Make an event wrapper. You will need to create an event in your user control that is raised when DataGridView CellDoubleClick (or any) is rased and in your calling code you will handle this event wrapper.
The second approach is more logical, cos internal logic of your control is incapsulated and you can provide end-user of you component with more logical and meaningful event then CellDoubleClidk or else.
thank u 4 your reply. Sorry for not responding earlier. I did manage to sort this issue out by creating a public event in my UC:
public event DataGridViewCellEventHandler GridRowDoubleClick {
add { dgvTasks.CellDoubleClick += value; }
remove { dgvTasks.CellDoubleClick -= value; }
}
and in my main form, after I instantiate and load the UC
_ucTask.GridRowDoubleClick += new DataGridViewCellEventHandler(TasksGrid_CellDoubleClick);
with the following attached event:
private void TasksGrid_CellDoubleClick( object sender, DataGridViewCellEventArgs e ) {
// do work here!
}
This does work, although I don't know if any of u experts out there foresee a problem with this approach.