Click here to Skip to main content
15,886,258 members
Articles / Desktop Programming / WPF

The WPF Podcatcher Series - Part 2 (Structural Skinning)

Rate me:
Please Sign up or sign in to vote.
4.97/5 (58 votes)
5 Mar 2008CPOL16 min read 252.8K   7.2K   166  
The second article in a series devoted to a WPF application that plays streaming audio podcasts off the Internet. This article discusses the idea and implementation of look-less applications.
<UserControl 
  x:Class="Podder.DefaultSkin.Views.MainWindowView_Episodes"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:podder="clr-namespace:Podder"
  xmlns:views="clr-namespace:Podder.DefaultSkin.Views"
  >
  <DockPanel Margin="4">
    <DockPanel DockPanel.Dock="Top">
      <Button 
        DockPanel.Dock="Right" 
        Command="{x:Static podder:Commands.RefreshEpisodes}" 
        Content="{podder:ResourceString MainWindowView_RefreshEpisodesButtonText}" 
        Margin="0,0,0,8" 
        />
      <TextBlock>
        <Run Text="{podder:ResourceString CurrentlyPlayingEpisode_Header}" />
        <Hyperlink Command="{x:Static podder:Commands.SelectActiveEpisode}" ToolTip="{podder:ResourceString CurrentlyPlayingEpisode_HyperlinkTooltip}">
          <Hyperlink.Style>
            <Style TargetType="Hyperlink">
              <Style.Triggers>
                <Trigger Property="IsEnabled" Value="False">
                  <Setter Property="Foreground" Value="Black" />
                  <Setter Property="TextDecorations" Value="" />
                </Trigger>
                <Trigger Property="IsEnabled" Value="True">
                  <Setter Property="FontWeight" Value="DemiBold" />
                </Trigger>
              </Style.Triggers>
            </Style>
          </Hyperlink.Style>
          <TextBlock Text="{Binding Path=EpisodePlayerSettings.ActiveEpisode.Name, FallbackValue={podder:ResourceString NoActiveEpisodeText}}" />
        </Hyperlink>
      </TextBlock>
    </DockPanel>

    <ListView 
      x:Name="_podcastListView" 
      DataContext="{Binding Path=Podcasts.CurrentItem}" 
      IsSynchronizedWithCurrentItem="True" 
      ItemsSource="{Binding Path=Episodes}"
      ScrollViewer.HorizontalScrollBarVisibility="Hidden"
      >
      <ListView.Resources>
        <views:TimeSpanToDisplayTextConverter x:Key="EpisodeDurationConverter" />
      </ListView.Resources>
      <ListView.InputBindings>
        <KeyBinding Key="Enter" Command="{x:Static podder:Commands.PlaySelectedEpisode}" />
      </ListView.InputBindings>
      <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
          <Setter Property="BorderBrush" Value="LightGray" />
          <Setter Property="BorderThickness" Value="0,0,0,0.8" />
        </Style>
      </ListView.ItemContainerStyle>
      <ListView.View>
        <GridView AllowsColumnReorder="False">
          <GridView.ColumnHeaderTemplate>
            <DataTemplate>
              <TextBlock Text="{TemplateBinding Content}" FontStyle="Italic" Margin="4,0" />
            </DataTemplate>
          </GridView.ColumnHeaderTemplate>
          <GridView.ColumnHeaderContainerStyle>
            <Style TargetType="GridViewColumnHeader">
              <Setter Property="Background" Value="LightGray" />
              <Setter Property="HorizontalContentAlignment" Value="Left" />
              <Setter Property="IsHitTestVisible" Value="False" />
            </Style>
          </GridView.ColumnHeaderContainerStyle>
          <GridViewColumn Header="{podder:ResourceString MainWindowView_FavoriteColumnHeader}">
            <GridViewColumn.CellTemplate>
              <DataTemplate>
                <CheckBox IsChecked="{Binding Path=IsFavorite}" Margin="5,0,0,0" />
              </DataTemplate>
            </GridViewColumn.CellTemplate>
          </GridViewColumn>
          <GridViewColumn Header="{podder:ResourceString MainWindowView_FinishedColumnHeader}">
            <GridViewColumn.CellTemplate>
              <DataTemplate>
                <CheckBox IsChecked="{Binding Path=IsFinished}" Margin="18,0,0,0" />
              </DataTemplate>
            </GridViewColumn.CellTemplate>
          </GridViewColumn>
          <GridViewColumn Header="{podder:ResourceString MainWindowView_EpisodeNameColumnHeader}" Width="10000">
            <GridViewColumn.CellTemplate>

              <DataTemplate>
                <TextBlock x:Name="txt" Text="{Binding Path=Name}" ToolTipService.ShowDuration="1200000">
                  <TextBlock.ContextMenu>
                    <ContextMenu>
                      <!-- 
                      The reason this menu item says "External Program" is because the episode's WebPageUrl property might
                      refer to a Web page or to the MP3 file itself. To keep things simple, we do not specify the target app.
                      -->
                      <MenuItem Header="{podder:ResourceString OpenInExternalProgramText}" Command="Open" CommandParameter="{Binding Path=WebPageUrl}" InputGestureText="">
                        <MenuItem.Icon>
                          <Image Source="Images\WebPage.png" Width="16" Height="16" />
                        </MenuItem.Icon>
                      </MenuItem>
                    </ContextMenu>
                  </TextBlock.ContextMenu>
                  <TextBlock.ToolTip>
                    <TextBlock>
                      <TextBlock MaxWidth="400" Text="{Binding Path=Description}" TextWrapping="Wrap" />
                      <LineBreak />
                      <LineBreak />
                      <TextBlock Text="{podder:ResourceString EpisodeTooltip_PublishedHeader}" />
                      <TextBlock Text="{Binding Path=PubDate}" />
                      <LineBreak />
                      <TextBlock Text="{podder:ResourceString EpisodeTooltip_DurationHeader}" />
                      <TextBlock>
                        <TextBlock.Style>
                          <Style TargetType="TextBlock">
                            <Setter Property="Text" Value="{Binding Path=Duration, Converter={StaticResource EpisodeDurationConverter}}" />
                            <Style.Triggers>
                              <DataTrigger Binding="{Binding Path=HasDuration}" Value="False">
                                <Setter Property="Text" Value="{podder:ResourceString EpisodeTooltip_DurationNotAvailable}" />
                              </DataTrigger>
                            </Style.Triggers>
                          </Style>
                        </TextBlock.Style>
                      </TextBlock>                        
                      <LineBreak />
                      <TextBlock Text="{podder:ResourceString EpisodeTooltip_FileSizeHeader}" />
                      <TextBlock Text="{Binding Path=Size}" />
                      <TextBlock Text="{podder:ResourceString EpisodeTooltip_MegaBytesAbbreviation}" />
                      <LineBreak />
                      <LineBreak />
                      <TextBlock Text="{podder:ResourceString EpisodeTooltip_DoubleClickToPlay}" />
                      <LineBreak />
                      <TextBlock Text="{podder:ResourceString EpisodeTooltip_RightClickToOpen}" />                         
                    </TextBlock>
                  </TextBlock.ToolTip>                        
                </TextBlock>

                <DataTemplate.Triggers>
                  <DataTrigger Binding="{Binding IsActive}" Value="True">
                    <Setter TargetName="txt" Property="FontWeight" Value="Bold" />
                  </DataTrigger>
                </DataTemplate.Triggers>
              </DataTemplate>

            </GridViewColumn.CellTemplate>
          </GridViewColumn>
        </GridView>
      </ListView.View>
    </ListView>
  </DockPanel>
</UserControl>

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

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


Written By
Software Developer (Senior)
United States United States
Josh creates software, for iOS and Windows.

He works at Black Pixel as a Senior Developer.

Read his iOS Programming for .NET Developers[^] book to learn how to write iPhone and iPad apps by leveraging your existing .NET skills.

Use his Master WPF[^] app on your iPhone to sharpen your WPF skills on the go.

Check out his Advanced MVVM[^] book.

Visit his WPF blog[^] or stop by his iOS blog[^].

See his website Josh Smith Digital[^].

Comments and Discussions