Vibrant discussion about CSLA .NET and using the framework to build great business applications.
I have just completely lost my cool in trying to get Microsoft's ComboBox control to work as I would *naturally* expect it to.
BackgroundThis extends on from the work Rocky did about a year ago for the Microsoft ComboBox control of previous versions of Silverlight. Essentially it didn't support the concept of SelectedValue and SelectedValuePath which is essential for FK / Lookup scenarios that use only the Id / Key and so Rocky had to roll his own implementation (refer http://www.lhotka.net/weblog/SilverlightComboBoxControlAndDataBinding.aspx).
Fastforward to Silverlight 4 and Microsoft annouces they've fixed all the ComboBox issues and added SelectedValue and SelectedValuePath support in SL4.
"Yay... but wait, not so fast!"
Disclaimer:When binding directly to SelectedIndex property, the ComboBox works like a dream, but forget about it when using the new SelectedValue and SelectedValuePath.
Issues:
Sure I can (and I have received repeated comments to) just not bother with the Microsoft ComboBox and use those from control suites like Telerik or Component one, but that immediately places dependencies of code, contract, funds, maintainability, etc. on a 3rd party vendor. Sometime I generally avoid, unless I absolutely have to.
Besides, I simply believe that something as rudimentary as a ComboBox should work right!
And so I have spent more time than I care to admit (or afford) trying to get to the bottom of this and make it work for me. I very nearly came to a solution where you simply have to change the control and do nothing else: E.g.
<ComboBox ... />
becomes
<custom:ComboBox ... />
But I just couldn't make it work... came close though, but in the end you have to not bind to SelectedValue (the root / axis of all this Evil) and instead bind to SelectedValueProper. E.g.
<ComboBox SelectedValue="{Binding Path=Id, Mode=TwoWay}" ... />
<custom:ComboBox SelectedValueProper="{Binding Path=Id, Mode=TwoWay}" ... />
Here's the full class listing - use as you wish, but for obvious reasons, only on the condition that I cannot be held liable. Note while this takes concepts from Rocky's implementation for the previous Silverlight version (I think SL2) of the Combox this code below is for the Silverlight 4 version of the ComboBox.
Hope that helps someone else too (then I would feel vindicated!) Jaans
public class ComboBoxEx : ComboBox { #region Fields private bool _suppressSelectionChangedUpdatesRebind = false; #endregion #region Properties public static readonly DependencyProperty SelectedValueProperProperty = DependencyProperty.Register( "SelectedValueProper", typeof( object ), typeof( ComboBoxEx ), new PropertyMetadata( ( o, dp ) => { var comboBoxEx = o as ComboBoxEx; if ( comboBoxEx == null ) return; comboBoxEx.SetSelectedValueSuppressingChangeEventProcessing( dp.NewValue ); } ) ); [Browsable( true ), EditorBrowsable( EditorBrowsableState.Always )] public object SelectedValueProper { get { return (object)GetValue( SelectedValueProperProperty ); } set { SetValue( SelectedValueProperProperty, value ); } } #endregion #region Constructor and Overrides public ComboBoxEx() { SelectionChanged += ComboBoxEx_SelectionChanged; } /// <summary> /// Updates the current selected item when the <see cref="P:System.Windows.Controls.ItemsControl.Items"/> collection has changed. /// </summary> /// <param name="e">Contains data about changes in the items collection.</param> protected override void OnItemsChanged( System.Collections.Specialized.NotifyCollectionChangedEventArgs e ) { // Must re-apply value here because the combobox has a bug that // despite the fact that the binding still exists, it doesn't // re-evaluate and subsequently drops the binding on the change event SetSelectedValueSuppressingChangeEventProcessing( SelectedValueProper ); } #endregion #region Events private void ComboBoxEx_SelectionChanged( object sender, SelectionChangedEventArgs e ) { // Avoid recursive stack overflow if ( _suppressSelectionChangedUpdatesRebind ) return; if ( e.AddedItems != null && e.AddedItems.Count > 0 ) { //SelectedValueProper = GetMemberValue( e.AddedItems[0] ); SelectedValueProper = SelectedValue; // This is faster than GetMemberValue } // Do not apply the value if no items are selected (ie. the else) // because that just passes on the null-value bug from the combobox } #endregion #region Helpers /// <summary> /// Gets the member value based on the Selected Value Path /// </summary> /// <param name="item">The item.</param> /// <returns></returns> private object GetMemberValue( object item ) { return item.GetType().GetProperty( SelectedValuePath ).GetValue( item, null ); } /// <summary> /// Sets the selected value suppressing change event processing. /// </summary> /// <param name="newSelectedValue">The new selected value.</param> private void SetSelectedValueSuppressingChangeEventProcessing( object newSelectedValue ) { try { _suppressSelectionChangedUpdatesRebind = true; SelectedValue = newSelectedValue; } finally { _suppressSelectionChangedUpdatesRebind = false; } } #endregion }
Right now I'm experiencing similar issues!
I'm having problem with Combobox that is binded (ItremsSource, SelectedValue, SelectedValuePath) to a list (tried NVL and BLB), that is part of of Csla ViewModel<...>.Model property, but ONLY AFTER undo. I think my problem is this.
Quick solution is moving list from from Model to ViewModel, but that is writing much more code.
Btw, NotUndoable is not working in SL?
mesh
mesh: Btw, NotUndoable is not working in SL?
NotUndoable doesn't work with managed backing fields. If you want to use it, you need to use a private backing field and also override OnGetState/OnSetState.
Rocky
I'm feeling your pain. I have a form that has a Country combobox and depending on the Country selected I populate the province combobox and depending on the province I populate the Town combobox etc. This turn out to be a nightmare. Why couldn't the silverlight team just do this right from the beginning and why is there no fix. There is lot of people complaining about the stupid behaviour of the SL4 combobox.
I have used your custom combobox and it is working like you would expect a combobox to work. Thanks Jaans for the code you have definitely save me a lot of time.
+1 for being vindicated
Ps: Hannes, lyk my die boere moet mekaar maar help.
Hi Jaans,
Thank you for your work on the breakage of what should be a basic function from a combo box. I started my first SL4 RIA project and hit the wall several days ago and I have been looking for a solution this problem. Your solution appears to be best one I have seen and I have see a few. I have not needed to make a custom control in the past so I am have a problem with implementing your custom control. My project complies with no errors and I have no issues using in my view.xaml that is using the custom combo box but there something missing becuase it breaks at InitializeComponents(). Here is the error:
Error: Unhandled Error in Silverlight Application Code: 4004 Category: ManagedRuntimeError Message: Set property 'System.Windows.FrameworkElement.Style' threw an exception.
Is it possible for you to post a link to your complete implementation of your custom combo box? I sure hope the MS fixes this in SL5!
Thank you, Ricker
Hi Ricker
Just a rough guess based on the above, but I suspect you may have had a style for your old "<ComboBox />" and you are still applying that same style to the <ComboBoxEx /> without updating the type of the style
Would you mind posting the following?
Jaans
Hi Ricker - Have you managed to resolve your issue?
YES! Thank you, this has saved the day for me.
Bedankt voor de moeite Jaans
Dominiek
Hello Jaans,
I have not resolved my issue of properly using the custom combo box. I moved on to other aspects of the project and the SL page on have been working on, but I am now at the point where this is the last part of the SL page that does not work. I will re-attempt tonight in making this work. I searched the entire project for any styles that target the combobox and found none. I am sure it is something small that I am missing. Thank you for checking up on me.
Ricker
That's great Jaans, thanks!
On a similar note, is anybody else annoyed with the fact that the ComboBox doesn't support key press events? I don't need anything fancy, but just for it to function like a ComboBox does in any browser. I have tried wiring up the KeyUp event, but these events don't fire when the ComboBox is open, only when it's closed. It looks like the Popup control or whatever is inside the ComboBox is stealing those events.
Has anybody else solved this problem? (PS I know about the AutoComplete control, but that's not what I want...I just want a working ComboBox)
Is there any chance of a VB version?
Many Thanks
Hi Tracy
Unfortunately no, not one that I wrote anyway, but you have a couple of alternative options:
Hope that helps
Thank you!!!