wpfadornerrouted-commands

In wpf, can an adorner catch a routed command?


I have a listboxitem, which when clicked, produces an adorner holding a custom control made of a textbox label and a MediaElement. All is well and the selected movie plays. The listbox was subclassed into a custom control as "ChartCanvas".

My problem: I have the controls for the movie in a different part of the visual tree. It is simple to get the command to playmovie to the "ChartCanvas", but I do not know how to send this command to the overlaying adorner control.

The basic code that creates the adorner is:

public UIElementAdorner(UIElement adornedElement, UIElement element)
            : base(adornedElement)
        {
            m_element = element;
            _adornedElement = adornedElement as Border;

            if (_adornedElement is null)
                throw new ArgumentException("This adorner requires a Border element of 
                sizing in MeasureOverride and Arrangement.");

        }

        public void Add()
        {   // These commands are absolutely needed for correct MediaElement/Adorner usage.
            AddLogicalChild(m_element);
            AddVisualChild(m_element);  

       ... ...
        }

The ChartCanvas code for PlayMovieCommand:

private ICommand _playMovie;
        public ICommand PlayMovieCommand
        {
            get
            {
                if (_playMovie == null)
                {
                    _playMovie = new RelayCommand(
                        p => true,
                        p => this.PlayMovie());
                }
                return _playMovie;
            }
        }

private void PlayMovie()
        {   
            Commands.PlayMovieCommand.Execute(null,null);          
        }

And in the MovieControl adorner--this code is never reached:

public MovieControlForChartCanvas()
        {
            InitializeComponent();

            CommandBindings.Add(new CommandBinding(Commands.PlayMovieCommand, OnPlayMovieCommand));

        }

In short, how can an adorner catch a routedcommand?

Thank you for any help.


Solution

  • I am afraid you cannot implement this using routed commands as they are limited to searching the element tree from the focused element and up for an element that has a matching command binding.

    Instead you could raise an event or send a message from one component to the other. There are implementations available in the common MVVM frameworks if you don't want to implement your own one.

    You could for example use the EventAggregator in Prism.

    Make sure that you use a single instance of it in your application. If you haven't implemented dependency injection, you could for example define a static property in App.xaml.cs

    public partial class App : Application
    {
        public static Prism.Events.IEventAggregator EventAggregator { get; } 
            = new Prism.Events.EventAggregator();
    }
    

    You would then use it to subscribe to and publish events from different parts of your application.

    ChartCanvas (publish):

    App.EventAggregator.GetEvent<PlayMovieEvent>().Publish();
    

    Adorner (subcribe):

    App.EventAggregator.GetEvent<PlayMovieEvent>()
        .Subscribe(() => { /* play movie...*/ });
    

    The payload is just a simple type:

    public class PlayMovieEvent : Prism.Events.PubSubEvent { }
    

    You'll find more information about this in the docs.