MVVM pattern violation: MediaElement.Play()

前端 未结 3 549
南旧
南旧 2020-12-02 23:55

I understand that ViewModel shouldn\'t have any knowledge of View, but how can I call MediaElement.Play() method from ViewModel, other than having a reference to View (or di

3条回答
  •  春和景丽
    2020-12-03 00:38

    I use media element to play sounds in UI whenever an event occurs in the application. The view model handling this, was created with a Source property of type Uri (with notify property changed, but you already know you need that to notify UI).

    All you have to do whenever source changes (and this is up to you), is to set the source property to null (this is why Source property should be Uri and not string, MediaElement will naturally throw exception, NotSupportedException I think), then set it to whatever URI you want.

    Probably, the most important aspect of this tip is that you have to set MediaElement's property LoadedBehaviour to Play in XAML of your view. Hopefully no code behind is needed for what you want to achieve.

    The trick is extremely simple so I won't post a complete example. The view model's play function should look like this:

        private void PlaySomething(string fileUri)
        {
            if (string.IsNullOrWhiteSpace(fileUri))
                return;
            // HACK for MediaElement: to force it to play a new source, set source to null then put the real source URI. 
            this.Source = null;
            this.Source = new Uri(fileUri);
        }
    

    Here is the Source property, nothing special about it:

        #region Source property
    
        /// 
        /// Stores Source value.
        /// 
        private Uri _Source = null;
    
        /// 
        /// Gets or sets file URI to play.
        /// 
        public Uri Source
        {
            get { return this._Source; }
            private set
            {
                if (this._Source != value)
                {
                    this._Source = value;
                    this.RaisePropertyChanged("Source");
                }
            }
        }
    
        #endregion Source property
    

    As for Visibility, and stuff like this, you can use converters (e.g. from bool to visibility, which you can find on CodePlex for WPF, SL, WP7,8) and bind your control's property to that of the view model's (e.g. IsVisible). This way, you control parts of you view's aspect. Or you can just have Visibility property typed System.Windows.Visibility on your view model (I don't see any pattern breach here). Really, it's not that uncommon.

    Good luck,

    Andrei

    P.S. I have to mention that .NET 4.5 is the version where I tested this, but I think it should work on other versions as well.

提交回复
热议问题