Click here to Skip to main content
15,881,649 members
Articles / Programming Languages / C# 4.0

A WPF Television Application

Rate me:
Please Sign up or sign in to vote.
4.75/5 (7 votes)
30 Apr 2010CPOL3 min read 45K   1.5K   43   5
An article that presents a TV Player via WPF

Introduction

Sometimes, many question the use of Silverlight and WPF over Flash technology. One advantage that Silverlight and WPF have is that they are technologies that can receive high-definition video/audio streams to play them. Graphics normally point to still images, as do photographs. Video, however (in TV) uses a frame rate of around 60 frames of an image per second to fool the eye into seeing a motion picture. A television signal is transmitted with the video and audio signals synchronized. That signal is received by the television receiver and stepped (in voltage) by something called the heterodyne principle. The video images and audio are retraced to form a motion picture. So how would we form a TV application using WPF? This article assumes that the reader has a working knowledge of WPF. It presents a WPF application that models a television. The GUI depicts a 3-D-looking environment feature a TV (or an image of) that be turned on to play, pause, and stop the TV's video. When the video plays, a semitransparent reflection plays simultaneously. While this is complex, it is actually a basic WPF GUI application built using controls and modified appearances. In this case, the example demonstrates the use of WPF bitmap effects to apply visual effects to some of the GUI elements. This application, however, is not an attempt to build a Windows Media Player in disguise in the form of a WPF application; it also introduces opacity masks, which can be used to hide parts of an element.

When you download this file, you will watch a video named "future_nasa.wmv". This can be downloaded from here. Add that  file to the video folder, and ensure that the video's property settings are correct: Copy to Output: always; File Name: future_nasa.wmv; FilePath, etc. You will notice this title in the markup XAML file:

XML
<Window x:Class="TV.TVWindow"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   Title="TV" Height="720" Width="720">
   <Window.Resources>
        
      <ControlTemplate x:Key="RadioButtonTemplate"
         TargetType="RadioButton">
         <Grid>
           <Ellipse Width="25" Height="25" Fill="Silver" />
             <Ellipse Name="backgroundEllipse" Width="22" Height="22">
               <Ellipse.Fill>
                 <RadialGradientBrush>
                    <GradientStop Offset="0" Color="Red"/>
                      <GradientStop Offset="1.25" Color="Black" />
                  </RadialGradientBrush>
               </Ellipse.Fill>
            </Ellipse>   
              
            <ContentPresenter Content="{TemplateBinding Content}" />
         </Grid> 
     
         <ControlTemplate.Triggers>
            
            <Trigger Property="RadioButton.IsEnabled" Value="False">
               <Setter TargetName="backgroundEllipse" Property="Fill">
                  <Setter.Value>
                     <RadialGradientBrush>
                      
                        <GradientStop Offset="0" Color="LightGray" />
                        <GradientStop Offset="1.25" Color="Black" />
                     </RadialGradientBrush>
                  </Setter.Value>
               </Setter>
            </Trigger> 
          
            <Trigger Property="RadioButton.IsChecked" Value="True">
               <Setter TargetName="backgroundEllipse" Property="Fill">
                  <Setter.Value>
                     <RadialGradientBrush>
                        <GradientStop Offset="0" Color="LimeGreen" />
                        <GradientStop Offset="1.25" Color="Black" />
                     </RadialGradientBrush>
                  </Setter.Value>
               </Setter>
            </Trigger>
         </ControlTemplate.Triggers>
      </ControlTemplate>
   </Window.Resources>
   <Canvas>
           <Border Canvas.Left="150" Height="370" Width="490" 
         Canvas.Top="20" Background="DimGray">
         <Grid>
            <Grid.RowDefinitions>
               <RowDefinition />
               <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>  
        
            <Border Margin="0,20,0,10" Background="Black"
               HorizontalAlignment="Center" VerticalAlignment="Center"
               BorderThickness="2" BorderBrush="Silver" CornerRadius="2">
               <MediaElement Height="300" Width="400"
                  Name="videoMediaElement" Source="Video/future_nasa.wmv"
                  LoadedBehavior="Manual" Stretch="Fill" />
            </Border>
         
            <StackPanel Grid.Row="1" HorizontalAlignment="Right"
               Orientation="Horizontal">
               <RadioButton Name="playRadioButton" IsEnabled="False"
                  Margin="0,0,5,15" Checked="playRadioButton_Checked"
                  Template="{StaticResource RadioButtonTemplate}">
                  <Image Height="20" Width="20"
                     Source="Images/play.png" Stretch="Uniform" />
               </RadioButton>
               <RadioButton Name="pauseRadioButton" IsEnabled="False"
                  Margin="0,0,5,15" Checked="pauseRadioButton_Checked"
                  Template="{StaticResource RadioButtonTemplate}">
                  <Image Height="20" Width="20"
                     Source="Images/pause.png" Stretch="Uniform" />
               </RadioButton>
               <RadioButton Name="stopRadioButton" IsEnabled="False"
                  Margin="0,0,15,15" Checked="stopRadioButton_Checked"
                  Template="{StaticResource   
                 RadioButtonTemplate}">
                  <Image Height="20" Width="20"
                     Source="Images/stop.png" Stretch="Uniform" />
               </RadioButton>
            </StackPanel>
  
            <CheckBox Name="powerCheckBox" Grid.Row="1" Width="25"
               Height="25" HorizontalAlignment="Left"
               Margin="15,0,0,15" Checked="powerCheckBox_Checked"
               Unchecked="powerCheckBox_Unchecked">
                
               <CheckBox.Template>
                  <ControlTemplate TargetType="CheckBox">
                     <Grid>
                        
                        <Ellipse Width="25" Height="25"
                           Fill="Silver" /> 
                        
                        <Ellipse Name="backgroundEllipse" Width="22"
                           Height="22">
                           <Ellipse.Fill>
                              
                              <RadialGradientBrush>
                                
                                 <GradientStop Offset="0"
                                    Color="LightGray" />
                                 <GradientStop Offset="1.25"
                                    Color="Black" />
                              </RadialGradientBrush>
                           </Ellipse.Fill>
                        </Ellipse> 
                       
                        <Image Source="Images/power.png" Width="20"
                           Height="20" />
                     </Grid>
 
          <ControlTemplate.Triggers> 
                  <Trigger Property="CheckBox.IsChecked"
                           Value="True">
                           <Setter TargetName="backgroundEllipse"
                              Property="Fill">
                              <Setter.Value>
                               
                                 <RadialGradientBrush>
                                    <GradientStop Offset="0"
                                       Color="LimeGreen" />
                                    <GradientStop Offset="1.25"
                                       Color="Black" />
                                 </RadialGradientBrush>
                              </Setter.Value>
                           </Setter>
                        </Trigger>
                     </ControlTemplate.Triggers>
                  </ControlTemplate>
               </CheckBox.Template>
            </CheckBox>
         </Grid>  
          
         <Border.RenderTransform>
            <SkewTransform AngleY="15" />
         </Border.RenderTransform>
           <Border.BitmapEffect>
            <BitmapEffectGroup>
             <BevelBitmapEffect BevelWidth="10" />
               <DropShadowBitmapEffect Color="Gray" ShadowDepth="15" Softness="1"/>
            </BitmapEffectGroup>
         </Border.BitmapEffect>
      </Border>
     
      <Border Canvas.Left="185" Canvas.Top="410" Height="300"
         Width="400">
         <Rectangle Name="reflectionRectangle">
            <Rectangle.Fill>
             
               <VisualBrush
                  Visual="{Binding ElementName=videoMediaElement}">
                  <VisualBrush.RelativeTransform>
                     <ScaleTransform ScaleY="-1" CenterY="0.5" />
                  </VisualBrush.RelativeTransform>
               </VisualBrush>
            </Rectangle.Fill>
            
            <Rectangle.OpacityMask>
               <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                  <GradientStop Color="Black" Offset="-0.25" />
                  <GradientStop Color="Transparent" Offset="0.5" />
               </LinearGradientBrush>
            </Rectangle.OpacityMask>
         </Rectangle>
 
      <Border.RenderTransform> 
            <SkewTransform AngleY="15" AngleX="-45"/>
         </Border.RenderTransform>
      </Border>
   </Canvas>
</Window> 

The control on the lower-left side of the TV turns the TV on, and the arrow control loads the video, in this case, a video of a rocket being launched to the moon. Here is an image of the GUI elements of the TV. The TV buttons in this example are not Button controls. The play, pause, and stop buttons are RadioButtons, and the power button is a CheckBox. This should make sense. Those controls have a difference in shape, but perform nearly the same function and usually come in groups. In the background of each button are two circles, defined by Ellipse objects. The images used are back, play, pause and stop symbols on a transparent background. In its default state, (enabled and unchecked), each playback button glows red. You first hit the Power button on the far left to turn the TV on, (i.e., check box unchecked), the control is gray. When the user clicks that button, the control turns green. You then click the arrow radio button. A reflection is shown, and the video starts, as does the audio.

1.JPG

The functionality for this application comes from the code-behind file. When the use turns on the TV (i.e., checks the powerCheckBox), the reflection is made visible, and the playback options are enabled. when the user turns off the TV, the MediaElement's close method is called to close the media. In addition, the reflection is made invisible and the playback options are disabled. Whenever one of the RadioButtons that represent each playback option is checked, the MediaElement executes one of the event handlers, such as play video:

C#
// File:  TV.xaml.cs
using System.Windows;

namespace TV
{
   public partial class TVWindow : Window
   {      
      public TVWindow()
      {
         InitializeComponent();
      } 
      private void powerCheckBox_Checked( object sender, 
         RoutedEventArgs e )
      {
                  reflectionRectangle.Visibility = Visibility.Visible;
         playRadioButton.IsEnabled = true;
         pauseRadioButton.IsEnabled = true;
         stopRadioButton.IsEnabled = true;
      } 
      
      private void powerCheckBox_Unchecked( object sender, 
         RoutedEventArgs e )
      {         
         videoMediaElement.Close();     
         
         reflectionRectangle.Visibility = Visibility.Hidden;
         playRadioButton.IsChecked = false;
         pauseRadioButton.IsChecked = false;
         stopRadioButton.IsChecked = false;
         playRadioButton.IsEnabled = false;
         pauseRadioButton.IsEnabled = false;
         stopRadioButton.IsEnabled = false;
      } 

      // plays the video (as mentioned above)
      private void playRadioButton_Checked( object sender, 
         RoutedEventArgs e )
      {
         videoMediaElement.Play();
      } 

      private void pauseRadioButton_Checked( object sender, 
         RoutedEventArgs e )
      {
         videoMediaElement.Pause();
      } 
      
      private void stopRadioButton_Checked( object sender, 
         RoutedEventArgs e )
      {
         videoMediaElement.Stop();
      } 
   } 
} 

Note that this downloads as a deployed application that shows a video of a tech worker maneuvering in zero gravity. The reason that there is solution file to download is that the entire container of files, images, and video is too large to upload. I built these applications using a downloaded and burned ISO image of Visual Studio 2010. There is no reason, however, why they shouldn’t run on Visual Studio 2008, as that platform is compatible with .NET 3.5.

References

  • Professional Visual Studio 2008, by Joe Mayo
  • The Deitel Associates

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer Monroe Community
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Question:) Pin
ahmed_am5510-Oct-12 21:38
ahmed_am5510-Oct-12 21:38 
QuestionCannot run the setup program your provided. Pin
Johnson.Gao.1266-Mar-12 2:07
Johnson.Gao.1266-Mar-12 2:07 
QuestionUsing the media element Pin
Sokeji30-Mar-11 5:32
Sokeji30-Mar-11 5:32 
GeneralEscher Pin
Marc Clifton1-May-10 14:40
mvaMarc Clifton1-May-10 14:40 
GeneralRe: Escher Pin
Pierre Leclercq2-May-10 12:36
Pierre Leclercq2-May-10 12:36 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.