How can I prevent duplicates in a WPF Listbox control? - wpf

I have a WPF listbox control that is declaratively bound to a textbox. The listbox's ItemsSource is an ObservableCollection that is built from an XML file. I can easily prevent duplicate entries in the listbox when a new item is added because I can check for it in the "Add" button's Click event handler.
However, when an existing item's value is changed in the textbox (which obviously shows the listbox's selected item) to one that already exists in the list I want to prevent this, but I don't know how.
I'd appreciate help with this!

You can create your own validation rule by deriving from ValidationRule and apply it to your text box's binding. In the Validate method you can check for duplicates and return a ValidationResult of false to prevent the binding source from being updated.

Listen to the CollectionChanged event and check when the collection has been modified if there are any duplicates and remove them.
Also, you can take a look at this question and its' answer for an observable collection that also notifies you when its' items' properties change.
Edit:
If you don't want to use the collection I mentioned above, you can make sure your collection's items implement INotifyPropertyChanged and every time you add an item to the collection, listen to its PropertyChanged event. In the handler, you check if the property that changes is the one that is displayed in the ListBox and check if any other element has the same value of this property. If you find such an element, you either change the value of your property to its old value, or remove the element entirely, it depends on the logic of your application.

Related

Should a ViewModel control focus in the View

I have an ItemsControl binding to a collection in the ViewModel. As a result of user input, a new item gets added to the collection and this gets displayed on the View.
The item is also a View-ViewModel pair, the View contains a TextBox that I would like to receive focus immediately after being added to the collection.
How do I set the focus to a TextBox without referencing the View from within the ViewModel? Are attached properties the way to go here?
well you can do this by creating a behaviour..
have a look here to get an idea of behaviours controlling focus

wpf combobox prevent text changed

is there any way to prevent wpf combobox from changing its text after selection changed? I have a custom control that derives from combobox and I want to be able to set the text manually after selection changed, additionally I cannot prevent the base.OnSelectionChanged from being invoked (this does the trick but it has to stay there as a part of requirements)
In general the IsEditable and the IsReadOnly properties of ComboBox are used to control the level to which the display Text of the ComboBox is editable or selectable by the user.
In the msdn combobox (section remarks) you can read about it.
I had a similar issue to solve, here's how I did it:
My First ComboBox item is an object implementing NotifiyPropertyChanged, i can change its value at any time and it updates.
I put its IsEnabled to False so that the user cannot select it.
If you want this item to be displayed the same way as others even when disabled, design your ItemTemplate.
In the SelectionChanged handler, if the selected index 0, I do nothing.
If the selectedIndex is not the first, I do my computation with this index (including updating the first item's text) then I set SelectedIndex to 0.
Edit 2 : try to set the grid's IsHitTestVisible to False, and to True for the CheckBoxes.
Edit 1 : If the first solution doesn't work : So the core issue is that when you click on a row and not on a CheckBox, it triggers SelectionChange. What you have to do is to handle the tunnelling left click event : Add a handler (in xaml more simple than in code) to PreviewMouseLeftButtonDown, and in the handler get the OriginalSource of the MouseButtonEventArgs. First Check that we are in second choice (index:1) of the CheckBox by checking if the Original source or one of its visual parent is the the second CheckBoxItem. If its not then return. Now if the OriginalSource is a CheckBox or is a visual parent a CheckBox then do nothing Otherwise mark the event as handled.
NB : You'll have to use VisualTreeHelper.GetParent and write a sub that checks if a Dependency object or one of its parent is of a given type. (the top most parent is the Window, having Nothing/Null as parent.) This sub will return the right typed object if found, or Noting/Null if not found.

What are the best practices with Databinding and ObservableCollections in WPF?

I am using LinqToSql as my datasource, let’s say I query a list of programmers from a table and then loop through that data populating an ObservableCollection. (First question, is this part wrong? It just seems weird to query data into a list and then loop through it to populate another list)
Next, when I databind my ObservableCollection of programmers to a ListBox. Then I bind the selectedItem of the Listbox to a TextBox. I understand that when I select an item in the ListBox the textbox will be updated and when I make a change in the textbox, the ListBox will get updated and as a result the ObservableCollection that the listbox is bound to will also be updated.
What I don’t completely understand is what the best practice is to get the data from the OC back into my original datasource. Do I just loop through the observable collection commiting my changes by updating each record? That doesn’t seem terribly efficient.
Thanks so much for your help!
-Josh
This is purely a view-model issue. You have complete control over all the objects and properties on the data side of the fence. Sometimes you have a simple arrangement where the user can only edit a single record, databinding does all the work, and you just write it back to the database when the user clicks save.
If you have a lot more data being displayed and any one piece of it can be modified by the user, then it is probably wise for you to keep a dirty flag in the object itself that records whether any of the properties have been changed. That way, you can efficiently save back just the modified entries.
Since your objects probably support INotifyPropertyChanged and your collections are observable, you can even automatically detect and manage the dirty flag. Or it might be simpler to just set dirty to true in all of your setters.
In any case, this information can even be useful to the user. For example, a user-interface can show unsaved records in bold or with some other convention.
The ObservableCollection is not the only one collection which you could use in wpf. But it is standard collection allows wpf to automatically update ui item containers like ListBox on collection changes like addition or removal of an item. You can't do it with List.
When the user modifies a textbox in ListBoxItem the ObservableCollection is not updated cause you don't add or remove or reorder items in the collection. You change the property in one of the items.
The ListBox contains a list of ListBoxItem containers, one for each item in collection specified as an ItemsSource.
The DataContext of each ListBoxItem is set to the corresponding item stored in ObservableCollection. So, if you change the text in TextBox in code, the binding engine will change the property of that item specified for TextBox.Text in binding. Nothing to change or update for the ObservableCollection object.
In the setter of such item's property the PropertChanged event of INotifyPropertyChanged interface are usually raised. That is also the usual the place to set up a dirty flag. Then you could also commit changes immediately from there, keep some list of dirty objects or search for them on commit like:
items.Where(item => item.IsDirty)
Also there are good tools like Snoop and WPFInspector, which greatly help you to understand the wpf app visual tree and datacontexts for each element

Append Items to Databound ItemsControl in WPF

I've got a Combo Box that is databound to an ObservableCollection of items. I would like to have a default selected item that is (None) that would set the value of the property I've bound to "SelectedValue" to null.
I think there ought to be a way to achieve this with some combination of Style/DataTemplate/TemplateSelector. I'm trying to design this with MVVM in mind, so I'd like something that doesn't use codebehind and is as reusable as possible. I'd also like the benefits of the ObservableCollection (updating the collection causing the control to rebind) to remain intact.
Bonus part B:
I would like to also be able to append an extra visual element to the bottom of an ItemsControl as well. I was thinking it would be easy to change the DataTemplate if I knew how to trigger it on the last item of a collection. Willing to entertain other options here.
The simplest way I've found to do this is to insert a "special" value into the underlying collection, and display the "(None)" text when it's selected. Obviously then you need to run your binding through a converter to take this value into account and return null when it's selected. (See this question of mine which was a result of me trying to add an actual null value to a ComboBox's underlying collection.)
Having said that, it might actually be possible to do what you want with the CompositeCollection class. You could make a separate collection (with only one item - your Null item) and bind your ComboBox to both it and your original collection through the CompositeCollection.

How to change cell background in ListView when data changes?

I have ListView with binding on ObservableCollection which has INotifyPropertyChanged implemented. When user open window, data will be displayed but I want to change backgorund on cells where data was changed in meanwhile...
I have been trying with Data triggers, but they can be triggered just on certain values. I want to trigger when value changes, whatever value is.
Thanks
You can use DataTrigger for that. But you need to add corresponding IsDirty property to the ViewModel class and on the setter of your property you can check whether Data has been modified and fire the IsDirty. Which inturn fire DataTrigger and so the background.
For example if you got a FirstName property, you might need IsFirstNameDirty:bool There is no other easy way the WPF checks for your value changed from the intial one.

Resources