dotnet/wpf · error · ArgumentException

SR.ContextMenuInDifferentDispatcher

Error message

SR.ContextMenuInDifferentDispatcher

What it means

ContextMenuService.GetContextMenu reads the ContextMenu attached property from an element and throws ArgumentException(SR.ContextMenuInDifferentDispatcher) when the retrieved menu is non-null but belongs to a different Dispatcher (i.e., was created on another UI thread). Cross-thread use of a DependencyObject is forbidden in WPF.

Solutions

  1. Create the ContextMenu on the same thread (Dispatcher) as the element it will be attached to.
  2. Marshal work back with element.Dispatcher.Invoke/BeginInvoke before reading or assigning the menu.
  3. Rebuild the menu on the target thread instead of sharing a single instance across threads.
  4. Check cm.Dispatcher == element.Dispatcher before calling GetContextMenu if the menu's origin is uncertain.

Example fix

// before
var menu = ContextMenuService.GetContextMenu(element); // menu on other thread
// after
ContextMenu menu = null;
element.Dispatcher.Invoke(() => menu = ContextMenuService.GetContextMenu(element));
Defensive patterns

Strategy: validation

Validate before calling

ContextMenu cm = (ContextMenu)element.GetValue(ContextMenuService.ContextMenuProperty);
bool safe = cm == null || cm.Dispatcher == element.Dispatcher;

Type guard

static bool IsSameDispatcher(ContextMenu cm, DependencyObject el) => cm == null || cm.Dispatcher == el.Dispatcher;

Try / catch

try
{
    var menu = ContextMenuService.GetContextMenu(element);
}
catch (ArgumentException)
{
    // menu belongs to another Dispatcher; rebuild it on element's thread
}

Prevention

When it happens

Trigger: Calling ContextMenuService.GetContextMenu(element) where element.GetValue(ContextMenuProperty) returns a ContextMenu whose Dispatcher differs from element.Dispatcher — typically the menu was created on another UI thread.

Common situations: Multi-UI-thread WPF apps (multiple windows each with own Dispatcher) where a ContextMenu instance created on one thread is assigned to an element on another, or shared resource dictionaries across threads.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/bea9705a3ff8327a. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/ContextMenuService.cs:43

                        typeof(ContextMenuService), // Owner
                        new FrameworkPropertyMetadata((ContextMenu)null,
                                FrameworkPropertyMetadataOptions.None));

        /// <summary>
        ///     Gets the value of the ContextMenu property on the specified object.
        /// </summary>
        /// <param name="element">The object on which to query the ContextMenu property.</param>
        /// <returns>The value of the ContextMenu property.</returns>
        [AttachedPropertyBrowsableForType(typeof(DependencyObject))]
        public static ContextMenu GetContextMenu(DependencyObject element)
        {
            ArgumentNullException.ThrowIfNull(element);

            ContextMenu cm = (ContextMenu)element.GetValue(ContextMenuProperty);

            if ((cm != null) && (element.Dispatcher != cm.Dispatcher))
            {
                throw new ArgumentException(SR.ContextMenuInDifferentDispatcher);
            }

            return cm;
       }

        /// <summary>
        ///     Sets the ContextMenu property on the specified object.
        /// </summary>
        /// <param name="element">The object on which to set the ContextMenu property.</param>
        /// <param name="value">
        ///     The value of the ContextMenu property. If the value is of type ContextMenu, then
        ///     that is the ContextMenu that will be used (without any modification). If the value
        ///     is of any other type, then that value will be used as the content for a ContextMenu
        ///     provided by this service, and the other attached properties of this service
        ///     will be used to configure the ContextMenu.
        /// </param>
        public static void SetContextMenu(DependencyObject element, ContextMenu value)
        {

View on GitHub (pinned to 81131a70a4)