Archive

Posts Tagged ‘Persistence’

Fix: Silverlight Media Framework Player VolumeElement out of sync

I was just adding a storable (persistent) Volume property to the MediaPlayerView class used at ClipFlair’s MediaPlayerWindow (connected to the underlying SMF player’s VolumeLevel property), when I realized that after reloading saved state, the SMF player’s Volume control would show a different value than the value set to it (which I could confirm by flipping the MediaPlayer control and looking at its properties on the backpanel that the ClipFlair app features for each component and for the activity container itself).

It seems to be some bug in the SMF logic or in its default template, since the following fix makes the issue disappear. The trick is that at a descendent class from SMFPlayer (like the MediaPlayer class that ClipFlair’s MediaPlayerWindow uses), one can override the OnApplyTemplate method (a standard method in templated XAML-based controls at Silverlight and WPF) and call the UpdateVolumeElement method shown below.

That method temporarily sets the volume to another value than its current one (this is important, just setting again to the same value would be ignored), then set again the current value to force the VolumeElement control’s UI to update.

 

//Project: ClipFlair (http://ClipFlair.codeplex.com)
//Filename: MediaPlayer.cs
//Version: 20130211

using System;
using System.Linq;
using System.Windows;
using System.Windows.Media;

using Microsoft.SilverlightMediaFramework.Core;
using Microsoft.SilverlightMediaFramework.Core.Media;
using Microsoft.SilverlightMediaFramework.Core.Accessibility.Captions;
using Microsoft.SilverlightMediaFramework.Plugins.Primitives;

namespace ClipFlair.MediaPlayer
{

  public class MediaPlayer : SMFPlayer
  {

    public override void OnApplyTemplate()
    {
      base.OnApplyTemplate();

      //...
      UpdateVolumeElement(); //patch for SMF bug
    }

    protected void UpdateVolumeElement()
    {
      //patch for SMF to update VolumeElement UI with any already set VolumeLevel
      double volume = VolumeLevel;
      VolumeLevel = (volume == 1) ? 0.9 : 1;
      VolumeLevel = volume;
    }

//...

 

Update: While submitting this as a bug to SMF source site on Codeplex it came to me that I could try setting the VolumeElement’s VolumeLevel value directly at ApplyTemplate and indeed it works:

protected void UpdateVolumeElement() 
{ //patch for SMF to update VolumeElement UI with any already set VolumeLevel VolumeElement.VolumeLevel = VolumeLevel; }

IsolatedStorageSettings for WPF

System.IO.IsolatedStorageSettings doesn’t exist in WPF (only in Silverlight) but can easily be ported from Mono project’s Moonlight implementation (the Moonlight project home is at http://www.mono-project.com/Moonlight), as suggested at: http://groups.google.com/group/wpf-disciples/browse_thread/thread/4ed6c009f3fb7d69

I found that implementation at the following URL:

http://vega.frugalware.org/tmpgit/moon/class/System.Windows/System.IO.IsolatedStorage/IsolatedStorageSettings.cs

Did some modifications to IsolatedStorageSettings.cs to make it work with WPF (whether the application is deployed via ClickOnce or not):

    // per application, per-computer, per-user
    public static IsolatedStorageSettings ApplicationSettings {
      get {
        if (application_settings == null) {
          application_settings = new IsolatedStorageSettings (
            (System.Threading.Thread.GetDomain().ActivationContext!=null)?
              IsolatedStorageFile.GetUserStoreForApplication() : 
//for WPF, apps deployed via ClickOnce will have a non-null ActivationContext IsolatedStorageFile.GetUserStoreForAssembly());
} return application_settings; } } // per domain, per-computer, per-user public static IsolatedStorageSettings SiteSettings { get { if (site_settings == null) { site_settings = new IsolatedStorageSettings ( (System.Threading.Thread.GetDomain().ActivationContext!=null)? IsolatedStorageFile.GetUserStoreForApplication() :
//for WPF, apps deployed via ClickOnce will have a non-null ActivationContext IsolatedStorageFile.GetUserStoreForAssembly()); //IsolatedStorageFile.GetUserStoreForSite() works only for Silverlight
} return site_settings; } }

 

Note that you should also change the #if block at the top of that code to write

#if !SILVERLIGHT

Also can take a look at the following for custom settings storage:

http://f10andf11.blogspot.gr/2012/03/wpf-implement-isolatedstoragesettings.html

The resulting IsolatedStorageSettings.cs file for WPF (thanks to if !SILVERLIGHT block, the C# compiler will ignore it in Silverlight which has such class already) is included in the WPF_Compatibility layer at the ClipFlair source-code in http://clipflair.codeplex.com (checkout the “Client” subfolder in the source).

The WPF compatibility layer contains other goodies too like value coercion for Silverlight DependencyProperties using WPF-compatible syntax, so that your source code can stay source-level compatible with both WPF and Silverlight and be shared among respective projects.

%d bloggers like this: