Archive

Posts Tagged ‘Templates’

Fix: XAML – The member Content is not recognized or is not accessible

I was looking into some third-party code, upgrading it from Silverlight 4.x and was getting error ‘The member "Content" is not recognized or is not accessible’ at the following code part:

image

Looking it up, found that you don’t need to bind the Content property of a ContentPresenter at all if you put it inside the ControlTemplate of a ContentControl (a Button is such too).

Quoting from:

http://social.msdn.microsoft.com/Forums/silverlight/en-US/ee6e887d-5140-4d32-a532-3d16b7d879da/how-do-i-bind-contentpresenter-content?forum=silverlightarchieve

 

When you put a ContentPresenter in the ControlTemplate of a ContentControl, it automatically displays the Content of the templated control. For example, if you put a ContentPresenter in a ControlTemplate of a Button, the Content property of the ContentPresenter is implicitly bound to the Content of the Button that uses the ControlTemplate.

It is introduced in this MSDN article and have a sample in it, http://msdn.microsoft.com/en-us/library/system.windows.controls.contentpresenter.content(v=vs.95).aspx

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; }

HowTo: Load a XAML ResourceDictionary from a .NET assembly

Copying here my answer at:

http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/11a42336-8d87-4656-91a3-275413d3cc19

What seems to work for me is the following (copying from the source code of http://ClipFlair.codeplex.com [check out the FlipPanel project under “Client” subfolder])

note

I’m using Build Action = "Page" and Custom Tool="MSBuild:Compile" at the properties of Themes\DropDownTheme.xml and Themes\RotateHorizontalTheme.xaml, as was for Themes\Generic.xaml. Seems to work OK (probably this is faster at runtime compared to setting Build Action to Resource and telling it to not build it)

according to http://stackoverflow.com/questions/145752/what-are-the-various-build-action-settings-in-vs-net-project-properties-and-wh the Build Action = "Page" compiles the XAML into BAML (this seems to also apply to Silverlight 5)

* FlipPanel project, Themes\Generic.xaml

<ResourceDictionary
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 xmlns:local="clr-namespace:FlipPanel;assembly=FlipPanel">
 
  <ResourceDictionary.MergedDictionaries>
    <ResourceDictionary 
Source="/FlipPanel;component/Themes/RotateHorizontalTheme.xaml" /> </ResourceDictionary.MergedDictionaries>
<Style TargetType="local:FlipPanel"> <Setter Property="Template"
Value="{StaticResource FlipPanel_RotateHorizontalTemplate}"/> </Style> </ResourceDictionary>

* FlipPanel Project, Themes\RotateHorizontalTheme.xaml

<ResourceDictionary
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 xmlns:local="clr-namespace:FlipPanel;assembly=FlipPanel">
 
  <ControlTemplate x:Key="FlipPanel_RotateHorizontalTemplate" 
TargetType="local:FlipPanel"> <Grid> ... </Grid> </ControlTemplate> <Style x:Key="FlipPanel_RotateHorizontalStyle" TargetType="local:FlipPanel"> <Setter Property="Template"
Value="{StaticResource FlipPanel_RotateHorizontalTemplate}"/> </Style> </ResourceDictionary>

* FlipPanel Project, Themes\DropDownTheme.xaml

<ResourceDictionary
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 xmlns:local="clr-namespace:FlipPanel;assembly=FlipPanel">
 
  <ControlTemplate x:Key="FlipPanel_DropDownTemplate" 
TargetType="local:FlipPanel"> <Grid> ... </Grid> </ControlTemplate> <Style x:Key="FlipPanel_DropDownStyle" TargetType="local:FlipPanel"> <Setter Property="Template"
Value="{StaticResource FlipPanel_DropDownTemplate}"/> </Style> </ResourceDictionary>

* FlipPanel.Silverlight.Demo project, FlipPanelTest.xaml

<UserControl x:Class="FlipPanelTest.FlipPanelTest"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:flip="clr-namespace:FlipPanel;assembly=FlipPanel" >
 
  <UserControl.Resources>
    <ResourceDictionary>
      <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary 
Source="/FlipPanel;component/Themes/RotateHorizontalTheme.xaml" /> <ResourceDictionary
Source="/FlipPanel;component/Themes/DropDownTheme.xaml" /> </ResourceDictionary.MergedDictionaries>
</ResourceDictionary> </UserControl.Resources> <Grid x:Name="LayoutRoot" Background="White" Width="400"> <Grid.RowDefinitions> <RowDefinition Height="300"></RowDefinition> <RowDefinition Height="300"></RowDefinition> </Grid.RowDefinitions> <flip:FlipPanel x:Name="panel1" Grid.Row="0" BorderBrush="DarkOrange"
BorderThickness="3" CornerRadius="4" Margin="10" Background="White"
Template="{StaticResource FlipPanel_DropDownTemplate}" >
<!-- Style="{StaticResource FlipPanel_DropDownStyle}" -->
<flip:FlipPanel.FrontContent> <StackPanel Margin="6"> <TextBlock TextWrapping="Wrap" Margin="3" FontSize="16"
Foreground="DarkOrange"
>This is the front side of the FlipPanel.</TextBlock> <Button Margin="3" Padding="3" Content="Button One"></Button> <Button Margin="3" Padding="3" Content="Button Two"></Button> <Button Margin="3" Padding="3" Content="Button Three"></Button> <Button Margin="3" Padding="3" Content="Button Four"></Button> </StackPanel> </flip:FlipPanel.FrontContent> <flip:FlipPanel.BackContent> <Grid Margin="6"> <Grid.RowDefinitions> <RowDefinition Height="Auto"></RowDefinition> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <TextBlock TextWrapping="Wrap" Margin="3" FontSize="16"
Foreground="DarkMagenta"
>This is the back side of the FlipPanel.</TextBlock> <Button Grid.Row="2" Margin="3" Padding="10"
Content="Flip Back to Front" HorizontalAlignment="Center"
VerticalAlignment="Center" Click="cmdFlip1_Click"></Button> </Grid> </flip:FlipPanel.BackContent> </flip:FlipPanel> <flip:FlipPanel x:Name="panel2" Grid.Row="1" BorderBrush="DarkOrange"
BorderThickness="3" CornerRadius="4" Margin="10" Background="White"
Template="{StaticResource FlipPanel_RotateHorizontalTemplate}" >
<!-- Style="{StaticResource FlipPanel_RotateHorizontalStyle}" -->
<flip:FlipPanel.FrontContent> <StackPanel Margin="6"> <TextBlock TextWrapping="Wrap" Margin="3" FontSize="16"
Foreground="DarkOrange"
>This is the front side of the FlipPanel.</TextBlock> <Button Margin="3" Padding="3" Content="Button One"></Button> <Button Margin="3" Padding="3" Content="Button Two"></Button> <Button Margin="3" Padding="3" Content="Button Three"></Button> <Button Margin="3" Padding="3" Content="Button Four"></Button> </StackPanel> </flip:FlipPanel.FrontContent> <flip:FlipPanel.BackContent> <Grid Margin="6"> <Grid.RowDefinitions> <RowDefinition Height="Auto"></RowDefinition> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <TextBlock TextWrapping="Wrap" Margin="3" FontSize="16"
Foreground="DarkMagenta"
>This is the back side of the FlipPanel.</TextBlock> <Button Grid.Row="2" Margin="3" Padding="10"
Content="Flip Back to Front" HorizontalAlignment="Center"
VerticalAlignment="Center" Click="cmdFlip2_Click"></Button> </Grid> </flip:FlipPanel.BackContent> </flip:FlipPanel>
<flip:FlipPanel x:Name="panel3" Grid.Row="2" BorderBrush="DarkOrange"
BorderThickness="3" CornerRadius="4" Margin="10" Background="White" >
<!-- using default style here -->
<flip:FlipPanel.FrontContent> <StackPanel Margin="6"> <TextBlock TextWrapping="Wrap" Margin="3" FontSize="16"
Foreground="DarkOrange"
>This is the front side of the FlipPanel.</TextBlock> <Button Margin="3" Padding="3" Content="Button One"></Button> <Button Margin="3" Padding="3" Content="Button Two"></Button> <Button Margin="3" Padding="3" Content="Button Three"></Button> <Button Margin="3" Padding="3" Content="Button Four"></Button> </StackPanel> </flip:FlipPanel.FrontContent> <flip:FlipPanel.BackContent> <Grid Margin="6"> <Grid.RowDefinitions> <RowDefinition Height="Auto"></RowDefinition> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <TextBlock TextWrapping="Wrap" Margin="3" FontSize="16"
Foreground="DarkMagenta"
>This is the back side of the FlipPanel.</TextBlock> <Button Grid.Row="2" Margin="3" Padding="10"
Content="Flip Back to Front" HorizontalAlignment="Center"
VerticalAlignment="Center" Click="cmdFlip2_Click"></Button> </Grid> </flip:FlipPanel.BackContent> </flip:FlipPanel>



</Grid> </UserControl>

 

Note that I decided to prefix names with "FlipPanel_", not sure if there’s some better way (using XAML namespaces somehow) to avoid any conflicts when merging the dictionaries and resolving the resouces with "{StaticResource …}"

Also note that in each theme file I also provide a Style (that sets the corresponding Template property of the FlipPanel conrol) that one can use instead of using the Template directly. At that Style more FlipPanel control properties could be set to values appropriate for that template (the template defines a skeleton and the style dresses the pirate [skeleton] as somebody cleverly pointed out).

Note that Generic.xaml merges and uses the templat from one of the themes. Couldmake copies of files similar to Generic.xaml and reference the same template but with different values in the Style for other properties to make variations without resorting to Copy/Paste when multiple Themes use the same Template but restyle it a bit.

Another important note is that at Generic.xaml you must not use x:Key="FlipPanel_DefaultStyle" or anyother key at the default style, or the command

        public FlipPanel()
        {
            DefaultStyleKey = typeof(FlipPanel);
        }

won’t load the default style (which is needed when you don’t provide a Template or Style value at the consumer XAML (FlipPanelTest.xaml). Probably one can modify it to load a style by name instead of just by type (probably the issue was that it found multiple named styles applying to that type [both FlipPanel_RotateHorizontalStyle and FlipPanel_DefaultStyle] in the Generic.xaml), but removing the Key and using an unnamed style seems to do the trick.

%d bloggers like this: