i am using listView grouping based on an enum which {Updated and not Updated}. In my case, their is a button to call update I just want to disable if rows are in an updated group. See in the images.
The list that is present in updated section I want that the button should be disabled. I am using an example found in Here
IsEnabled={Binding ProperyNameOnYourViewModel, Mode=OneWay}
That will work assuming 1) your VM implements INotifyPropertyChanged and triggers appropriate event at the appropriate moment (typically, property's setter is responsible for that); 2) your control itself knows how to react on IsEnabled=false visually, i.e. changes color or whatever you like it to do.
Since you got an enum rather than bool, the easiest way to stick to the solution I've suggest is by extending your VM with yet another property, which recomputes boolean flag all the time. Then you might invoke PropertyChanged event not from your bool property (to which IsEnabled is actually bound), but from the enum property such that whenever it changes, WPF gets notified that boolean property has changed as well.
Otherwise, solve the problem with help of converters, which requires a lot more code.
Related
I'm developing a WPF/MVVM application and I have a listbox binding to data in a ViewModel. At various points I need the view model to cause the listbox to scroll to a given element.
How can I do this without creating a custom control and while still maintaining good separation of concerns?
I've currently got it working by creating a custom behavior class in the view layer with a dependency property VisibleIndex which the XAML code then binds to an integer in the view model:
<ListBox x:Name="myListBox"
local:ListBoxVisibilityBehavior.VisibleIndex="{Binding VisibleIndex}">
When the integer is set it triggers the dependency properties update handler which tells the listbox to scroll to the associated index.
This seems a bit hacky though because the dependency property value is never changed by the listbox and the update handler only gets called when the value changes, so the only way to ensure that the relevent item is visible is to do something like this:
// view-model code
this.VisibleIndex = -1;
this.VisibleIndex = 10;
The only reason I'm using a behaviour class at the moment is for binding my custom dependency property, is there a way to do something like this with events instead?
Attached properties are somewhat required in your case - as at some point, 'somewhere' you need to call the following method...
ListBox.ScrollIntoView(item)
or
ListBoxItem.BringIntoView();
And for that you need some sort of code behind - and attached properties/behaviors are a nice way of packaging that, w/o impacting your MVVM.
Having said that - if you just need to have your 'selected item' scrolled into view at all times (which is the case most of the time). Then you could use a different attached-property based solution (that again):
mvvm how to make a list view auto scroll to a new Item in a list view
All you have to do then is to set or bind to SelectedItem.
That's a bit 'nicer' if you wish - but the mechanism is the same.
For anyone else interested in the answer to this one of the MS engineers on the WPF forum cleared it up for me. Instead of binding to an event directly you bind to a wrapper object that encapsulates that event. The behaviour can then grab the reference to the wrapper from its DP and do whatever it wants with it i.e. subscribe to the event, trigger it etc.
I am working on an application that uses WPF/C# with MVVM. I have one particular ObservableCollection<> which is bound to ListBox.
Scenario 1: When the application is running, I modify this ObservableCollection<> and ListBox is populated as expected.
Scenario 2: With new requirements I have to fill this ListBox by default with some init values. So I have added a method for initializing it in my ViewModel. I call this method in OnStartup() after initializing View & ViewModel. DataContext is also set properly. In this scenario values are updated in the ObservableCollection<>, Unfortunately they are not reflected in the ListBox.
Just to verify if anything is wrong with the OnStartup(), I added the same method call in a callback on ContentRendered from the View, instead of OnStartup() it did work fine.
So my question, When exactly MVVM guarantees that all the bindings are setup correctly?
Edit:
One more observation, if I pop a message/dialog ListBox is populated as expected. It calls ContentRendered callback. And then it populates correctly.
I am almost convinced that ContentRendered should be the function that guarantees the bindings.
I can't say with certainty that this is your issue, without seeing the change to the code, but it sounds like you may now have an initial value of null for the property to which you are binding.
If you subsequently set that property to an ObservableCollection<T>, there is no automatic change notification.
One option would be to raise a notification that the property value changed (from null to something), and then let the ObservableCollection<T> handle change notification from there.
The better solution would be to initialize the property with an empty ObservableCollection<T> from the get-go, then your initialization to default values will mean adding those values and change notification should happen as you expect.
You might get the same problem by starting with a non-null collection, then setting the property to a new instance of a collection, without raising a notification, but I'm not 100 percent certain of that.
If this is not your issue, then I'll be happy to take another look.
Using MVVM, my viewmodel is my WPF window's data context. In the viewmodel is an observablecollection that holds the items in a listbox. When I add items to the collection, the listbox updates as expected
As part of my generic undo function, the observablecollection can be replaced with an older version. This happens by passing the collection to a method by reference and changing the reference. Everything after the undo works correctly except for the listbox. This continues to show data from the old reference.
How can I either stop this from happening or change the reference that the datacontext uses so that my listbox is "undone" and then continues working?
You need to provide some change notification in order to trigger the UI to update which you won't get from reassigning a ref variable to another instance. To get the notification you can either Clear and re-fill the original ObservableCollection instance or fire a PropertyChanged event for the collection property's name after swapping the instances.
Using the MVVM pattern, properties are changed in the ViewModel, with setters raising the PropertyChanged event. The event is handled in the View (automatically by WPF) and bindings are refreshed.
In your case, the value is being changed without the setter being called, so the PropertyChanged event (if it exists) is not being raised.
One option might be to manually raise the PropertyChanged event from the undo code. This would allow you to keep your existing design (please note that INotifyPropertyChanged.PropertyChanged is different to ObservableCollection.CollectionChanged - do a bit of research if this is not clear).
The second option would be to handle the CollectionChanged event, and keep a record of ItemsAdded and ItemsRemoved.
Your undo mechanism can then re-add any items which were removed, or remove any items which were added. This might require a bit of design tweaking.
I would go with the second design, as I think the design rethink might be a good idea. If you are using MVVM, you should be using Commands, and if you are using Commands you can implement Undo/Redo functionality neatly by extending the Commands (remember that an action made by a user is usually a bit more than a value change).
I am binding a ListView a property that essentially wraps the Values collection (ICollection) on a generic dictionary.
When the values in the dictionary change, I call OnNotifyPropertyChanged(property). I don't see the updates on the screen, with no binding errors.
When I change the property getter to return the Linq extension dictionary.Values.ToList(), without changing the signature of the property (ICollection) it works with no problem.
Any reason why the Values collection bind and notify properly without projecting to an IList<>?
Calling OnNotifyPropertyChanged() isn't exactly correct in this case, since the collection is still the same, however the items in the collection have changed. I don't know exactly how the WPF binding code works, but it might do a quick check to see if the reference it is binding to has changed, and if not it won't update the UI.
The reason that ToList() works is because each time it is called, a new instance of List<T> is returned, so when OnNotifyPropertyChanged() is fired, WPF picks up on the change and updates all of its bindings.
I don't know if this is possible or not, but the ideal solution would be to use a collection for bindings that implements INotifyCollectionChanged. This will fire events that WPF monitors so that items can be added, removed, etc. from the UI as appropriate.
Please tell me the basic and quick way to bind a Collection(List,etc) to a combobox and handle the selection changed event and get the selected item.
This is quite easy. You can do this with XAML+Code or just code. I won't type out a complete solution as I feel you'll benefit more from completing that part yourself. I've assumed here that you already have some XAML declaring a combo box, so I've just shown some code (in C# as you didn't state what language you were using), just know that the event handler could easily be assigned via XAML instead.
this.combo.SelectionChanged +=
new SelectionChangedEventHandler(comboProjects_SelectionChanged);
this.combo.ItemsSource = myCollectionOfItems;
This sets up an event handler for the selection changing and also binds the combo to a collection, which it uses to source its items (hence the name, ItemsSource).
Then, in the SelectionChanged event handler, you can get the SelectedItem property to find out what is selected.
Note that there are some caveats with binding in the ComboBox, so you may find these links useful:
http://silverlight.net/forums/t/63616.aspx
http://silverlight.net/forums/p/87111/202335.aspx#202335