My code is,
DestMenu.Add(SelectedMenu);
ObservableCollection<MenuModel> temp =
(ObservableCollection<MenuModel>)DestMenu.OrderBy(p =>(p.MenuName));
DestMenu = temp;
Here, SelectedMenu is the new item to be added to collection. temp is dummy collection to swap. And, when i try to convert the sorted collection, if any, to ObservableCollection, it throws some exception.
Can someone help me sort the collection and make me understand the problem in my code?
Thanks
Manikandan
I got the trick.
DestMenu.Add(SelectedMenu);
IEnumerable<MenuModel> temp = DestMenu.OrderBy(p =>(p.MenuName));
DestMenu = new ObservableCollection<MenuModel>(temp);
This works and the DestMenu has the sorted collection now.
Thanks
Manikandan
Well so sad that the OrderBy Extension Method doesn't sort the collection but returns an IOrderdEnumerable so to handle this you should do the following
DestMenu = new ObservableCollection<MenuModel>(DestMenu.OrderBy(o=>o.MenuName));
Of course using ObservableCollection you need items to be updated on the view that wont actually happened when you use this approach of sorting because ObservableCollection updates items on the view because it fires CollectionChanged Event but in fact we have changed the Collection itself not an element within the collection so it would be good if you did the following
public YourClass : INotifyPropertyChanged
{
void YourMethod()
{
DestMenu = new ObservableCollection<MenuModel>(DestMenu.OrderBy(o=>o.MenuName));
RaisePropertyChanged("DestMenu");
}
event PropertyChangedEventHandler PropertyChanged;
void RaisePropertyChanged(string PropertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(PropertyName));
}
}
Related
i am struggling with the mvvm data binding. I am not using any framework for the mvvm, I got a very basic base class for my view models. I uploaded my example-app with my problem to GitHub, find the link below.
My problem:
I got a simple app with an tab menu. there are 2 tabs called "TabA" and "TabB". Both views have a simple view model. The view models are referencing a manager class which holds the data. The Manager class has to objects (objects of my datamodel-class which just contains a string and implements INotifyPropertyChanged) in an observablecollection. There is also a Property in the Manager which references the current choosen object (its just one of the 2 objects from the list).
There are 2 actions which can be done by "TabB". The first one works as expected. If you enter some new string into the entry an hit the first button, it updates the string of the current choosen object and updates the label in TabA.
What is not working? With the second Button in my "TabB" class you switch the value of the current choosen object in the Manager. In the debugger I can see that the value is changed, but the Label in "TabA" does not recognize that it has to update the value.
Can you help me?
https://github.com/dercdev/MVVM-Xamarin
With the help of Jason I came to something like this:
In my TabAViewModel I subscribed the event of the Manager:
public TabAViewModel()
{
_mgr = Manager.Instance;
_mgr.PropertyChanged += new PropertyChangedEventHandler(obj_PropertyChanged);
}
Then I raise the event:
private void obj_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
OnPropertyChanged("CurrentData");
}
Which updates the label of the view.
Is that okay or is there a "better" way to do it?
As far as I know, the better way is to use INotifyPropertyChanged. If you want to implement Notify, I think you need to implement INotifyPropertyChanged interface, you can create one class name ViewModelBase that inheriting INotifyPropertyChanged, like this:
public class ViewModelBase:INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Then you can call RaisePropertyChanged method to inotify when property changed,
private string _text;
public string Text
{
get
{
return _text;
}
set
{
_text = value;
RaisePropertyChanged("Text");
}
}
ObservableCollection implements INotifyPropertyChanged, allowing the collection to notify the user when the contents of the collection have changed - and specifically, what changed within the collection. For example, if you add an item to the collection, the CollectionChanged event will be raised with properties that tell you the index of the new item as well as including the item in a list.
So ObservableCollection _list don't need to call RaisePropertyChanged method.
https://learn.microsoft.com/en-us/dotnet/api/system.collections.objectmodel.observablecollection-1.system-componentmodel-inotifypropertychanged-propertychanged?view=netframework-4.7.2
Is is possible to get an event when an item in the collection bound to a Xamarin Forms listview changes?
For example my object has a Date field which is bound to a label in a ViewCell. I would like an event fired when the Date is changed. Our object implements INotifyPropertyChanged so the listview updates properly.
I can manually subscribe to the OnPropertyChanged event of each item but I'm hoping their is an easier way.
Thanks.
There are triggers in Xamarin.Forms. It seems like an event trigger will do what you need. For example:
<EventTrigger Event="TextChanged">
<local:NumericValidationTriggerAction />
</EventTrigger>
public class NumericValidationTriggerAction : TriggerAction<Entry>
{
protected override void Invoke (Entry entry)
{
double result;
bool isValid = Double.TryParse (entry.Text, out result);
entry.TextColor = isValid ? Color.Default : Color.Red;
}
}
You can find more information about triggers here
See this example for deleting an object when it is selected from a list view.
private MyItemsViewModel _myItemsViewModel;
private void MyItemsListView_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
MyItem item = (MyItem)e.SelectedItem;
if (item == null)
return;
// remove the item from the ObservableCollection
_myItemsViewModel.Items.Remove(item);
}
I'm new to Xamarin and C#, so apologies in advance for any mistakes I make.
In my app, I have a list of plants. When a plant is selected, I have a detail view of info about the plant. In the detail view, I have a button that adds or removes the plant from a shopping list.
To implement this, I have a class named MyPlant, with a field called InCart, and a method ToggleInCart that the button calls.
(note that I didn't paste in some code to simplify this question as much as possible)
public class MyPlant : INotifyPropertyChanged
{
string name;
bool inCart;
...
public bool InCart
{
set
{
if (inCart != value)
{
inCart = value;
OnPropertyChanged("InCart");
}
}
get { return inCart; }
}
public ICommand ToggleCartStatus
{
get
{
if (_toggleCartStatus == null)
{
_toggleCartStatus = new Command(() => InCart = !InCart);
}
return _toggleCartStatus;
}
I have another class called PlantList, which has a method PlantsInCart that uses LINQ to return an ObservableCollection of MyPlant where InCart is true.
public class PlantList : INotifyPropertyChanged
{
public ObservableCollection PlantsInCart
{
private set { }
get
{
ObservableCollection list = new ObservableCollection(myPlants.Where(i => i.InCart));
return list;
}
}
In my XAML, I have a ListView bound to PlantsInCart.
Everything works as I want EXCEPT when I remove the selected plant, the list doesn't update to show the plant is missing even though the data underneath it is correctly updated. If I refresh the list by going to a different page and coming back, then the list shows the right plants.
I suspect this doesn't work because the change in the InCart field isn't bubbling up high enough to that the ListView hears that it is supposed to update.
Can anybody advise me on the proper way to implement this kind of feature? In other words, how should you implement a scenario where you have a list that should update when a property of an item in the list changes?
need some help, when i click the tap_event I get a message box delete or cancel which works and the price is taken off the total but it does'nt update the shopping cart after, it crashes on "ListBoxCart.Items.Remove(curr), thanks in advance!
private void listBoxCart_Tap(object sender, GestureEventArgs e)
{
if (MessageBox.Show("Are you sure!", "Delete", MessageBoxButton.OKCancel)
== MessageBoxResult.OK)
{
foreach (Dvd curr in thisapp.ShoppingCart)
{
if (curr.Equals(listBoxCart.SelectedItem))
{
listBoxCart.Items.Remove(curr);
listBoxCart.SelectedIndex = -1;
total -= Convert.ToDecimal(curr.price);
NavigationService.Navigate(new Uri("/ShoppingCart.xaml", UriKind.RelativeOrAbsolute));
}
}
txtBoxTotal.Text = total.ToString();
listBoxCart.ItemsSource = thisapp.ShoppingCart;
}
else
{
NavigationService.Navigate(new Uri("/ShoppingCart.xaml", UriKind.RelativeOrAbsolute));
}
}
I have wrote an artile (sorry in french but you can read the XAML) : http://www.peug.net/2012/05/17/contextmenu-dans-listbox-datatemplate/
and in the code-behind : an example :
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
var menuItem = sender as MenuItem;
var fe = VisualTreeHelper.GetParent(menuItem) as FrameworkElement;
Dvd _fig = fe.DataContext as Dvd;
thisapp.ShoppingCart.Remove(_fig);
reloading();
}
When you set the ItemsSource property for the ListBox, it generates a read-only collection and displays them. What you're trying to do is access this read-only collection and modify it but because it's read-only, you can't do that.
Instead you can either have your collection implement the INotifyCollectionChanged interface and raise a collection changed event when the user has deleted the item or use an ObservableCollection instead to store your items. ObservableCollection implements the INotifyCollectionChanged interface for you so you can remove items from the ObservableCollection and the changes will reflect in the Listbox automatically.
ObservableCollection also implements INotifyPropertyChanged so any property updates will also be updated in the ListBox.
Im getting crazy about this issue. I implemented a ListView which you can add/remove TextField dinamically, but only the last TextField is removed.
An example:
// Object type which is used in the list
public class ExampleObject implements Serializable{
private String keyword;
public String getKeyword() {
return this.keyword;
}
public void setKeyword(String s) {
keyword = s;
}
}
//ListView
List<ExampleObject> keywordList = new ArrayList<ExampleObject>();
keywordList.add(new ExampleObject());
ListView keywordView = new ListView("keywordView", keywordList) {
#Override
protected void populateItem(final ListItem item) {
ExampleObject model = (ExampleObject) item.getModelObject();
item.add(new TextField("subKeyword", new PropertyModel(model, "keyword")));
// keyword remove link
AjaxSubmitLink removeKeyword = new AjaxSubmitLink("removeKeyword", myForm)
{
#Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
ExampleObject selected = (ExampleObject) item.getModelObject();
// I also tried deleting by index. println shows the
// selected object is the element I want to remove, so why always
// remove last object of the list?
keywordList.remove(selected);
if (target != null) {
target.addComponent(myForm);
}
}
};
item.add(removeKeyword);
// keyword add link
AjaxSubmitLink addKeyword = new AjaxSubmitLink("addKeyword", metadataForm)
{
#Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
keywordList.add(new ExampleObject());
if (target != null) {
target.addComponent(myForm);
}
}
};
item.add(addKeyword);
}
keywordView.setReuseItems(true);
metadataForm.add(keywordView);
Any help would be very appreciate, because I thing this issue is really a very stupid mistake but I cant get it!
Thanks
It might be as simple as getting rid of the line
keywordView.setReuseItems(true);
The reuseItems flag is an efficiency so that the page does not rebuild the ListView items unnecessarily, but it can lead to confusion such as what you're seeing.
ListView really wasn't made for use with forms though, and you'll probably be better off with another tactic entirely.
This blog entry on building a list editor form component might be useful. It will need some changes if you're not on Wicket 1.4, but similar stuff is definitely possible in Wicket 1.3, and the comments have some hints.
Read the javadoc of ListView#setReuseItems():
"But if you modify the listView model object, than you must manually call listView.removeAll() in order to rebuild the ListItems."
You can not use a ListView this way. Either use the members of ListView provided:
removeLink(java.lang.String id, ListItem<T> item)
and
newItem(int index)
but, I never used those. If I have to display a List and be able to add remove Items dynamically, I prefer the RefreshingView.
If you do use FormComponents inside a RefreshingView, make sure you set a Reusestartegy (setItemReuseStrategy())
Bert