locked
Set the Text of a CommandBarComboBox RRS feed

  • Question

  • Hi there,

    I want to set the Text of a CommandBarComboBox.
    With DTE this was possible with:

    CommandBarComboBox dropdown; 
    // create etc..... dropdown.Text = "Some Text";

    But this is deprecated now. I've already found an answer (here) to GET the text, but how can I set it?
    Or is there a workaround to do this?

     

    Kind regards
    Simon

    Tuesday, May 24, 2011 12:46 PM

Answers

  • >It's depressing to develop this perfectly fine as an VS 2008 AddIn and then have to rewrite it as a package for VS 2010 and it doesn't work.. :(

    I agree it is unfortunate that it didn't 'just work' between 2008 and 2010, such is life occasionally.  As I said this was a resourcing / time issue, it's not like we had large periods of time we were sitting around twiddling our thumbs and just decided not to implement it to make people's lives miserable :)

    As for the QueryStatus mechanism, it is slighty more complex for a combo. We actually call Exec with a non-null out param to indicate what we are actually after is the display text for the item in the combo.  Combos are a bit weird in the overall commanding story and some of the interaction patterns like this are...really weird (if you ask me). They have been this way a long time (at least back as far as 2005 I believe).  You can set display text that isn't shown in the dropdown list, that is perfectly fine and there are at least a couple of combos in the shell that do this iirc it was one of the PITA issues with WPF as they DON'T allow combos to display an item that isn't in the child collection so making this work was kind of a pain.

    Ryan

    • Marked as answer by SWoker Wednesday, May 25, 2011 10:09 AM
    Tuesday, May 24, 2011 3:48 PM
  • Because of COM rules and WPF rules we don't allow for updating of the UI off the UI thread.  You can indicate that command UI is invalid (which will cause us to update it) by calling IVsUIShell::UpdateCommandUI passing in 0 (1 means update the UI synchronously, which is generally bad perf wise).  IVsUIShell must also be called on the UI thread. You can get to the UI thread from a background thread with ThreadHelper, specifically ThreadHelper.Generic.Invoke.

    Ryan

    • Marked as answer by SWoker Wednesday, May 25, 2011 3:24 PM
    Wednesday, May 25, 2011 2:43 PM

All replies

  • ComboBoxes aren' well supported via DTE due to lack of time / resource during the development of 2010 :(  I get questions on this maybe once a year out of tens of thousands of extenders, so it is very much a corner case.  In general, for more complex commanding scenarios, like combos, the suggestion is to write a package and use VSCT + the normal command QueryStatus/Exec mechanisms.  AddIns were always intended to be very lightweight, limited functionality and have a number of drawbacks in this area that make writing a package the better approach.

    Ryan

    Tuesday, May 24, 2011 3:03 PM
  • I've already tried the QueryStatus mechanism. It works fine if I'm loading the data on a button click, but I load it in a background thread, because it's rather slow (Query WorkItems from TFS). If I call the QueryStatus mechanism from the thread, the data in the dropdown changes, but the text itself is not changed and I cannot select an item programatically.
    Also it would be great if the text itself is not selectable as an item... but I just don't know how to do this.

    It's depressing to develop this perfectly fine as an VS 2008 AddIn and then have to rewrite it as a package for VS 2010 and it doesn't work.. :(

    Tuesday, May 24, 2011 3:16 PM
  • >It's depressing to develop this perfectly fine as an VS 2008 AddIn and then have to rewrite it as a package for VS 2010 and it doesn't work.. :(

    I agree it is unfortunate that it didn't 'just work' between 2008 and 2010, such is life occasionally.  As I said this was a resourcing / time issue, it's not like we had large periods of time we were sitting around twiddling our thumbs and just decided not to implement it to make people's lives miserable :)

    As for the QueryStatus mechanism, it is slighty more complex for a combo. We actually call Exec with a non-null out param to indicate what we are actually after is the display text for the item in the combo.  Combos are a bit weird in the overall commanding story and some of the interaction patterns like this are...really weird (if you ask me). They have been this way a long time (at least back as far as 2005 I believe).  You can set display text that isn't shown in the dropdown list, that is perfectly fine and there are at least a couple of combos in the shell that do this iirc it was one of the PITA issues with WPF as they DON'T allow combos to display an item that isn't in the child collection so making this work was kind of a pain.

    Ryan

    • Marked as answer by SWoker Wednesday, May 25, 2011 10:09 AM
    Tuesday, May 24, 2011 3:48 PM
  • I didn't accuse you of making people's live miserable on purpose, so don't worry :)

    Anyway, your answer helped me a lot already! There were some problems in the code I've tried before, because the QueryStatus gets executed multiple times and it has simply overriden the text I've set.
    It works now from the background thread too, but it only updates the text in the UI when I click somewhere.

    I've already tried:

    • Application.DoEvents() - no effect at all
    • SynchronizationContext.Send() - I get a NullReference Exception, but I cannot see where, because it's outside of my thread and I cannot catch it.
      This is the Stacktrace:
      System.Transactions Critical: 0 : <TraceRecord xmlns="http://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord" Severity="Critical"><TraceIdentifier>http://msdn.microsoft.com/TraceCodes/System/ActivityTracing/2004/07/Reliability/Exception/Unhandled</TraceIdentifier><Description>Unhandled exception</Description><AppDomain>DefaultDomain</AppDomain><Exception><ExceptionType>System.NullReferenceException, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType><Message>Object reference not set to an instance of an object.</Message><StackTrace>  at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteBackoutCodeHelper(Object backoutCode, Object userData, Boolean exceptionThrown)
        at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
        at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
        at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
        at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
        at System.Windows.Threading.DispatcherOperation.Invoke()
        at System.Windows.Threading.Dispatcher.ProcessQueue()
        at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean&amp;amp; handled)
        at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean&amp;amp; handled)
        at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
        at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
        at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
        at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
        at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)</StackTrace><ExceptionString>System.NullReferenceException: Object reference not set to an instance of an object.
        at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteBackoutCodeHelper(Object backoutCode, Object userData, Boolean exceptionThrown)
        at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
        at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
        at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
        at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
        at System.Windows.Threading.DispatcherOperation.Invoke()
        at System.Windows.Threading.Dispatcher.ProcessQueue()
        at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean&amp;amp; handled)
        at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean&amp;amp; handled)
        at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
        at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
        at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
        at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
        at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)</ExceptionString><DataItems><Data></Data></DataItems></Exception></TraceRecord>

    So I hope there is some other way how I can Invalidate the Dropdown from a background thread?
    If not I can still go with the "click somewhere and the text will be shown" approach, but it would be nicer to do this automatically of course.

    Wednesday, May 25, 2011 10:09 AM
  • Because of COM rules and WPF rules we don't allow for updating of the UI off the UI thread.  You can indicate that command UI is invalid (which will cause us to update it) by calling IVsUIShell::UpdateCommandUI passing in 0 (1 means update the UI synchronously, which is generally bad perf wise).  IVsUIShell must also be called on the UI thread. You can get to the UI thread from a background thread with ThreadHelper, specifically ThreadHelper.Generic.Invoke.

    Ryan

    • Marked as answer by SWoker Wednesday, May 25, 2011 3:24 PM
    Wednesday, May 25, 2011 2:43 PM