연습: WPF Designer를 사용하여 비디오 브라우저 빌드
이 연습에서는 WPF Designer for Visual Studio를 사용하여 비디오 파일을 찾아볼 수 있는 WPF 응용 프로그램을 만드는 방법을 보여 줍니다.
이 연습에서는 다음 작업을 수행합니다.
프로젝트를 만듭니다.
레이아웃을 만듭니다.
레이아웃에 컨트롤을 추가합니다.
레이아웃 관련 속성을 설정합니다.
데이터 소스 형식을 만듭니다.
WPF 컨트롤을 만듭니다.
응용 프로그램에서 컨트롤을 사용합니다.
응용 프로그램 논리를 구현합니다.
데이터 바인딩을 사용합니다.
응용 프로그램의 스타일을 지정합니다.
다음 그림에서는 응용 프로그램의 모양을 보여 줍니다.
이 연습을 마치면 폴더에서 WMV(Windows Media Player) 파일을 찾아보는 데 사용할 수 있는 응용 프로그램이 만들어집니다. .wmv 파일마다 동일한 이름의 .jpg 파일이 있어야 합니다. 예를 들어 bear.wmv 파일이 있으면 bear.jpg 파일도 같은 폴더에 있어야 합니다.
참고
표시되는 대화 상자와 메뉴 명령은 활성 설정이나 버전에 따라 도움말에서 설명하는 것과 다를 수 있습니다. 설정을 변경하려면 도구 메뉴에서 설정 가져오기 및 내보내기를 선택합니다. 자세한 내용은 설정에 대한 작업을 참조하십시오.
참고
다음은 이 소스 코드/예제의 소유자이자 작성자인 Application Developers Training Company의 승인 하에 다시 발간한 것입니다. 원본은 코스웨어 "Developing Applications for Visual Studio 2008"(Ken Getz 지음, Copyright 2007 Application Developers Training Company)에 들어 있습니다. 자세한 내용은 http://www.appdev.com을 참조하십시오.
사전 요구 사항
이 연습을 완료하려면 다음 구성 요소가 필요합니다.
- Visual Studio 2010.
프로젝트 만들기
첫 번째 단계로 호스트 응용 프로그램에 대한 프로젝트를 만듭니다. MoviePlayerControl은 MediaElement 및 비디오 재생을 조작하기 위한 다른 컨트롤이 포함된 UserControl입니다.
프로젝트를 만들려면
VideoBrowser라는 WPF 응용 프로그램 프로젝트를 만듭니다. 자세한 내용은 방법: 새 WPF 응용 프로그램 프로젝트 만들기를 참조하십시오.
WPF Designer에 MainWindow.xaml이 열립니다.
새 WPF 사용자 정의 컨트롤 라이브러리 프로젝트를 솔루션에 추가합니다. 프로젝트 이름을 MoviePlayerControlLibrary로 지정합니다. 자세한 내용은 방법: WPF UserControl 라이브러리 프로젝트 만들기를 참조하십시오.
MoviePlayerControlLibrary 프로젝트에서 MoviePlayerControl이라는 새 WPF 사용자 정의 컨트롤을 추가합니다. 자세한 내용은 방법: WPF 프로젝트에 새 항목 추가를 참조하십시오.
프로젝트에서 UserControl1을 삭제합니다.
레이아웃 만들기
레이아웃은 응용 프로그램의 주 창에 컨트롤이 정렬되는 방식을 정의합니다. 다음 단계에서는 응용 프로그램의 컨트롤이 포함될 레이아웃 요소를 생성하는 방법을 보여 줍니다.
레이아웃을 만들려면
WPF Designer에서 MediaPlayerControl.xaml을 엽니다.
사용자 정의 컨트롤의 루트 Grid 컨트롤을 선택합니다. 자세한 내용은 방법: 디자인 화면의 요소 선택 및 이동을 참조하십시오.
속성 창에서 루트 Grid 컨트롤의 이름을 moviePlayerGrid로 설정합니다. Name 속성이 속성 창 위쪽에 설정됩니다.
moviePlayerGrid에 행을 두 개 추가합니다. 자세한 내용은 방법: 표에 행 및 열 추가를 참조하십시오.
문서 개요 창에서 moviePlayerGrid의 첫 번째 행을 선택하고 MinHeight 속성을 50으로 설정합니다.
moviePlayerGrid의 두 번째 행을 선택하고 Height 속성을 20으로 설정합니다.
moviePlayerGrid의 세 번째 행을 선택하고 Height 속성을 55로 설정합니다.
도구 상자에서 Grid 컨트롤을 moviePlayerGrid의 세 번째 행에 끌어 놓습니다.
WPF Designer에 grid1이라는 새 Grid 컨트롤이 만들어집니다.
속성 창에서 grid1의 이름을 mediaControlsGrid로 설정합니다.
mediaControlsGrid의 Margin 속성을 0으로 설정합니다.
속성 창에서 ColumnDefinitions 컬렉션 편집기를 열고 다섯 개의 열 정의를 추가합니다.
도구 상자에서 StackPanel 컨트롤을 mediaControlsGrid의 마지막 열에 끌어 놓습니다.
WPF Designer에 stackPanel1이라는 새 StackPanel 컨트롤이 만들어집니다.
문서 개요 창을 열어 레이아웃을 확인합니다. 자세한 내용은 WPF 문서의 요소 계층 탐색를 참조하십시오.
개체 계층 구조가 다음과 같아야 합니다.
Grid (moviePlayerGrid)
RowDefinitions
Grid (mediaControlsGrid)
ColumnDefinitions
StackPanel (stackPanel1)
개체 계층 구조가 이 패턴을 따르지 않으면 이 계층 구조가 될 때까지 개체를 끌거나 XAML을 수정합니다.
레이아웃에 컨트롤 추가
이제 정의된 레이아웃을 컨트롤로 채울 수 있습니다. 도구 상자에서 원하는 컨트롤을 클릭하고 디자인 화면에 끌어 놓기만 하면 됩니다.
레이아웃에 컨트롤을 추가하려면
도구 상자에서 MediaElement 컨트롤을 moviePlayerGrid의 첫 번째 행에 끌어 놓습니다.
속성 창에서 속성을 다음과 같이 설정합니다.
Property
값
Name
moviePlayer
Margin
0
Width
Auto
Height
Auto
HorizontalAlignment
Stretch
VerticalAlignment
Stretch
LoadedBehavior
수동
도구 상자에서 Button 컨트롤을 mediaControlsGrid의 첫 번째 열에 끌어 놓습니다.
속성 창에서 속성을 다음과 같이 설정합니다.
Property
값
Name
backButton
Content
뒤로
Margin
0
도구 상자에서 Button 컨트롤을 mediaControlsGrid의 두 번째 열에 끌어 놓습니다.
속성 창에서 속성을 다음과 같이 설정합니다.
Property
값
Name
playButton
Content
재생
Margin
0
도구 상자에서 Button 컨트롤을 mediaControlsGrid의 세 번째 열에 끌어 놓습니다.
속성 창에서 속성을 다음과 같이 설정합니다.
Property
값
Name
stopButton
Content
Stop
Margin
0
도구 상자에서 Button 컨트롤을 mediaControlsGrid의 네 번째 열에 끌어 놓습니다.
속성 창에서 속성을 다음과 같이 설정합니다.
Property
값
Name
forwardButton
Content
Fwd
Margin
0
도구 상자에서 TextBlock 컨트롤을 mediaControlsGrid의 다섯 번째 열에 끌어 놓습니다.
속성 창에서 속성을 다음과 같이 설정합니다.
Property
값
Text
Volume
Width
Auto
Height
Auto
HorizontalAlignment
Center
VerticalAlignment
Stretch
도구 상자에서 Slider 컨트롤을 mediaControlsGrid의 다섯 번째 열에 끌어 놓습니다.
속성 창에서 속성을 다음과 같이 설정합니다.
Property
값
Name
volumeSlider
Width
Auto
Height
Auto
최소
0
Maximum
1
Margin
5
도구 상자에서 Slider 컨트롤을 moviePlayerGrid의 두 번째 행에 끌어 놓습니다.
속성 창에서 속성을 다음과 같이 설정합니다.
Property
값
Name
positionSlider
Width
Auto
Height
Auto
최소
0
Maximum
1
Margin
2
HorizontalAlignment
Stretch
VerticalAlignment
Stretch
이벤트 처리기 추가
응용 프로그램에서는 이벤트를 처리하여 사용자 입력에 응답합니다. 다음 절차에서는 MoviePlayerControl의 컨트롤에 의해 발생한 이벤트에 대한 이벤트 처리기를 추가하는 방법을 보여 줍니다. 자세한 내용은 방법: 단순한 이벤트 처리기 만들기를 참조하십시오.
이벤트 처리기를 추가하려면
XAML 뷰에서 <MediaElement> 태그 내에 커서를 놓고 MediaOpened=를 입력합니다.
Intellisense에서 <새 이벤트 처리기> 옵션을 표시합니다.
**<새 이벤트 처리기>**를 선택합니다.
WPF Designer가 코드 파일에 moviePlayer_MediaOpened 이벤트 처리기를 만듭니다.
MediaEnded 이벤트에 대해 1단계와 2단계를 반복합니다.
디자인 뷰에서 positionSlider를 두 번 클릭합니다.
WPF Designer가 코드 파일에 positionSlider_ValueChanged 이벤트 처리기를 만듭니다.
디자인 뷰에서 backButton을 두 번 클릭합니다.
WPF Designer가 코드 파일에 backButton_Click 이벤트 처리기를 만듭니다.
나머지 단추 컨트롤을 두 번 클릭하여 각 컨트롤에 대해 Click 이벤트 처리기를 생성합니다.
positionSlider를 두 번 클릭하여 ValueChanged 이벤트 처리기를 생성합니다.
MoviePlayerControl에 대한 논리 구현
MoviePlayerControl.xaml.cs 또는 MoviePlayerControl.xaml.vb라는 코드 파일에서 MoviePlayerControl에 대한 논리를 구현합니다.
MoviePlayerControl에 대한 논리를 구현하려면
솔루션 탐색기에서 MoviePlayerControl.xaml.cs 또는 MoviePlayerControl.xaml.vb를 두 번 클릭하여 코드 편집기에서 코드 파일을 엽니다.
MoviePlayerControl 클래스 정의에서 생성자 앞에 다음 코드를 삽입합니다.
' Specifies whether the movie is playing. Private playing As Boolean ' Used to update the position slider's current value. Private timer As New System.Windows.Threading.DispatcherTimer()
// Specifies whether the movie is playing. private bool playing; // Used to update the position slider's current value. private System.Windows.Threading.DispatcherTimer timer = new System.Windows.Threading.DispatcherTimer();
MoviePlayerControl 클래스 정의에서 이벤트 처리기 정의 뒤에 다음 코드를 삽입합니다.
#Region "Utility Methods" Private Sub timer_Tick(ByVal sender As Object, ByVal e As EventArgs) ' The DispatcherTimer's Tick event handler runs ' in the UI thread, so you can work with the UI ' without worrying about cross-thread issues. positionSlider.Value = moviePlayer.Position.TotalMilliseconds End Sub Private Sub PlayMovie() If Not playing Then ' The Play method will begin the media if it is not currently active or ' resume media if it is paused. This has no effect if the media is ' already running. moviePlayer.Play() playButton.Content = "Pause" playing = True Else moviePlayer.Pause() playButton.Content = "Play" playing = False End If End Sub Private Sub StopMovie() ' The Stop method stops and resets the media to be played from ' the beginning. moviePlayer.Stop() moviePlayer.Position = TimeSpan.Zero playButton.Content = "Play" playing = False End Sub #End Region
#region Utility Methods void timer_Tick(object sender, EventArgs e) { // The DispatcherTimer's Tick event handler runs // in the UI thread, so you can work with the UI // without worrying about cross-thread issues. positionSlider.Value = moviePlayer.Position.TotalMilliseconds; } private void PlayMovie() { if (!playing) { // The Play method will begin the media if it is not currently active or // resume media if it is paused. This has no effect if the media is // already running. moviePlayer.Play(); playButton.Content = "Pause"; playing = true; } else { moviePlayer.Pause(); playButton.Content = "Play"; playing = false; } } private void StopMovie() { // The Stop method stops and resets the media to be played from // the beginning. moviePlayer.Stop(); moviePlayer.Position = TimeSpan.Zero; playButton.Content = "Play"; playing = false; } #endregion
자동으로 생성된 이벤트 처리기를 다음 코드로 바꿉니다.
Private Sub moviePlayer_MediaOpened(ByVal sender As Object, ByVal e As RoutedEventArgs) ' Put code here that runs when the media ' is first opened. ' Set the media's starting Volume to the current ' value of the slider control. moviePlayer.Volume = System.Convert.ToDouble(volumeSlider.Value) positionSlider.Maximum = moviePlayer.NaturalDuration.TimeSpan.TotalMilliseconds ' Update the position slider every second. timer.Interval = New TimeSpan(0, 0, 1) timer.Start() End Sub Private Sub moviePlayer_MediaEnded(ByVal sender As Object, ByVal e As RoutedEventArgs) ' Media playback is finished. ' Stop the media to seek to media start. StopMovie() timer.Stop() End Sub Private Sub positionSlider_ValueChanged(ByVal sender As Object, ByVal e As RoutedPropertyChangedEventArgs(Of Double)) ' Create a TimeSpan with milliseconds equal to the slider value. Dim ts As New TimeSpan(0, 0, 0, 0, Fix(positionSlider.Value)) moviePlayer.Position = ts ' Jump back 5 seconds: moviePlayer.Position = moviePlayer.Position.Subtract(New TimeSpan(0, 0, 0, 0, 5000)) positionSlider.Value = moviePlayer.Position.TotalMilliseconds End Sub Private Sub backButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) ' Jump back 5 seconds: moviePlayer.Position = _ moviePlayer.Position.Subtract(New TimeSpan(0, 0, 0, 0, 5000)) positionSlider.Value = _ moviePlayer.Position.TotalMilliseconds End Sub Private Sub playButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) PlayMovie() End Sub Private Sub stopButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) StopMovie() End Sub Private Sub forwardButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) ' Jump ahead 5 seconds: moviePlayer.Position = moviePlayer.Position.Add(New TimeSpan(0, 0, 0, 0, 5000)) positionSlider.Value = moviePlayer.Position.TotalMilliseconds End Sub Private Sub volumeSlider_ValueChanged(ByVal sender As Object, ByVal e As RoutedPropertyChangedEventArgs(Of Double)) moviePlayer.Volume = System.Convert.ToDouble(volumeSlider.Value) End Sub
private void moviePlayer_MediaOpened(object sender, RoutedEventArgs e) { // Put code here that runs when the media // is first opened. // Set the media's starting Volume to the current // value of the slider control. moviePlayer.Volume = (double)volumeSlider.Value; positionSlider.Maximum = moviePlayer.NaturalDuration.TimeSpan.TotalMilliseconds; // Update the position slider every second. timer.Interval = new TimeSpan(0, 0, 1); timer.Start(); } private void moviePlayer_MediaEnded(object sender, RoutedEventArgs e) { // Media playback is finished. // Stop the media to seek to media start. StopMovie(); timer.Stop(); } private void positionSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { // Create a TimeSpan with milliseconds equal to the slider value. TimeSpan ts = new TimeSpan( 0, 0, 0, 0, (int)positionSlider.Value); moviePlayer.Position = ts; } private void backButton_Click(object sender, RoutedEventArgs e) { // Jump back 5 seconds: moviePlayer.Position = moviePlayer.Position.Subtract(new TimeSpan(0, 0, 0, 0, 5000)); positionSlider.Value = moviePlayer.Position.TotalMilliseconds; } private void playButton_Click(object sender, RoutedEventArgs e) { PlayMovie(); } private void stopButton_Click(object sender, RoutedEventArgs e) { StopMovie(); } private void forwardButton_Click(object sender, RoutedEventArgs e) { // Jump ahead 5 seconds: moviePlayer.Position = moviePlayer.Position.Add(new TimeSpan(0, 0, 0, 0, 5000)); positionSlider.Value = moviePlayer.Position.TotalMilliseconds; } private void volumeSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { moviePlayer.Volume = (double)volumeSlider.Value; }
자동으로 생성된 생성자를 다음 코드로 바꿉니다.
Public Sub New() InitializeComponent() ' Initialize the timer's Tick event handler: AddHandler timer.Tick, AddressOf timer_Tick End Sub
public MoviePlayerControl() { InitializeComponent(); // Initialize the timer's Tick event handler: timer.Tick += new EventHandler(timer_Tick); }
다음 메서드를 삽입하여 컨트롤의 공용 인터페이스를 정의합니다.
Public Sub PlayMovie(ByVal movie As Uri) moviePlayer.Source = movie PlayMovie() End Sub Public Sub Close() StopMovie() moviePlayer.Close() End Sub
public void PlayMovie(Uri movie) { moviePlayer.Source = movie; PlayMovie(); } public void Close() { StopMovie(); moviePlayer.Close(); }
F6 키를 눌러 컨트롤을 빌드합니다.
데이터 소스 형식 만들기
데이터 바인딩을 사용하여 컨트롤을 데이터에 연결합니다. 이 응용 프로그램에서는 비디오 브라우저의 ListBox 컨트롤이 ThumbnailList라는 사용자 지정 클래스에 바인딩됩니다.
데이터 소스 형식을 만들려면
VideoBrowser 프로젝트에 ThumbnailList라는 새 클래스를 추가합니다.
코드 편집기에서 ThumbnailList.cs 또는 ThumbnailList.vb를 열고 자동으로 생성된 코드를 다음 코드로 바꿉니다.
Imports System Imports System.Collections.Generic Imports System.Text Imports System.IO Imports System.Collections.ObjectModel Imports System.ComponentModel Imports System.Windows.Media.Imaging Imports System.Collections.Specialized Imports System.Windows.Controls Public Class ThumbnailList Inherits ObservableCollection(Of String) ' Can't set the path in the constructor, ' because the main form uses static binding to ' bind to an instance of this class, which gets ' created before the form (and therefore, before ' you've specified a folder). If you create a new ' instance of this class when you supply the path ' name, the static binding is now binding to the original ' (empty) collection. Therefore, this code must ' allow you to modify the folder for the existing ' instance of this class. Private _folderName As String ' Public Property FolderName() As String Get Return _folderName End Get Set _folderName = value ' Now fill in the collection of ' file names: Me.Clear() Dim fileName As String For Each fileName In Directory.GetFiles(Me.FolderName, "*.jpg") Me.Add(fileName) Next fileName End Set End Property End Class
using System; using System.Collections.Generic; using System.Text; using System.IO; using System.Collections.ObjectModel; using System.ComponentModel; using System.Windows.Media.Imaging; using System.Collections.Specialized; using System.Windows.Controls; namespace VideoBrowser { public class ThumbnailList : ObservableCollection<String> { // Can't set the path in the constructor, // because the main form uses static binding to // bind to an instance of this class, which gets // created before the form (and therefore, before // you've specified a folder). If you create a new // instance of this class when you supply the path // name, the static binding is now binding to the original // (empty) collection. Therefore, this code must // allow you to modify the folder for the existing // instance of this class. String _folderName; public string FolderName { get { return _folderName; } set { _folderName = value; // Now fill in the collection of // file names: this.Clear(); foreach (string fileName in Directory.GetFiles(this.FolderName, "*.jpg")) { this.Add(fileName); } } } } }
VideoBrowser 프로젝트에 FileToURIConverter라는 새 클래스를 추가합니다.
코드 편집기에서 FileToURIConverter.cs 또는 FileToURIConverter.vb를 열고 자동으로 생성된 코드를 다음 코드로 바꿉니다.
Imports System Imports System.Collections.Generic Imports System.Linq Imports System.Text Imports System.Windows.Data Imports System.Windows.Media.Imaging Namespace VideoBrowser Class FileToURIConverter Implements IValueConverter Public Function Convert( _ ByVal value As Object, _ ByVal targetType As Type, _ ByVal parameter As Object, _ ByVal culture As System.Globalization.CultureInfo) As Object _ Implements IValueConverter.Convert ' In design mode, value is not a string, so it is ' important to check input parameters. If CType(value, String) IsNot Nothing Then ' Convert from the image name to a BitmapFrame ' for display in the list. Return BitmapFrame.Create(New Uri(value.ToString())) Else Return Nothing End If End Function Public Function ConvertBack( _ ByVal value As Object, _ ByVal targetType As Type, _ ByVal parameter As Object, _ ByVal culture As System.Globalization.CultureInfo) As Object _ Implements IValueConverter.ConvertBack Throw New NotImplementedException() End Function End Class End Namespace
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Data; using System.Windows.Media.Imaging; using System.ComponentModel; namespace VideoBrowser { class FileToURIConverter : IValueConverter { public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { // In design mode, value is not a string, so it is // important to check input parameters. if (value is string) { // Convert from the image name to a BitmapFrame // for display in the list. return BitmapFrame.Create(new Uri(value.ToString())); } else { return null; } } public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } } }
모든 파일을 저장합니다.
응용 프로그램에서 컨트롤 사용
컨트롤을 만들었으면 응용 프로그램에서 컨트롤을 사용할 수 있습니다.
WPF 컨트롤을 사용하려면
솔루션 탐색기의 VideoBrowser 프로젝트에 MoviePlayerControlLibrary 프로젝트에 대한 참조를 추가합니다. 자세한 내용은 프로젝트 참조를 참조하십시오.
System.Windows.Forms 어셈블리에 대한 참조를 추가합니다. 이 참조는 FolderBrowserDialog에 필요합니다.
MainWindow.xaml을 열고 XAML 뷰에서 자동으로 생성된 코드를 다음 코드로 바꿉니다.
<Window x:Class="VideoBrowser.MainWindow" Name="window1" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" xmlns:media = "clr-namespace:MoviePlayerControlLibrary;assembly=MoviePlayerControlLibrary" xmlns:vb="clr-namespace:VideoBrowser" Title="Video Browser" Height="540" Width="383"> <Window.Resources> <vb:FileToURIConverter x:Key="myConverter" /> <DataTemplate x:Key="imageTemplate"> <Border VerticalAlignment="Center" HorizontalAlignment="Center" Padding="4" Margin="2" Background="White"> <Image Source="{Binding Converter={StaticResource myConverter}}" /> </Border> </DataTemplate> <!--<ResourceDictionary > <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="Resources.xaml"/> </ResourceDictionary.MergedDictionaries> <vb:FileToURIConverter x:Key="myConverter" /> <DataTemplate x:Key="imageTemplate"> <Border VerticalAlignment="Center" HorizontalAlignment="Center" Padding="4" Margin="2" Background="White"> <Image Source="{Binding Converter={StaticResource myConverter}}" /> </Border> </DataTemplate> </ResourceDictionary>--> </Window.Resources> <Grid Name="grid1"> <Grid.RowDefinitions> <RowDefinition Height="125" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <Grid Margin="0" Name="grid2"> <Grid.ColumnDefinitions> <ColumnDefinition Width="115" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Button x:Name="selectFolderButton" Click="selectFolderButton_Click">Select folder...</Button> <ListBox Grid.Column="1" Margin="0,0,0,0" Name="videoListBox" SelectionChanged ="videoListBox_SelectionChanged" ItemTemplate="{StaticResource imageTemplate}" ItemsSource="{Binding ElementName=window1, Path=Thumbnails}" /> </Grid> <media:MoviePlayerControl x:Name="moviePlayer" Grid.Row="1" /> </Grid> </Window>
MainWindow.xaml.cs 또는 MainWindow.xaml.vb라는 코드 파일을 열고 코드 편집기에서 자동으로 생성된 코드를 다음 코드로 바꿉니다.
Imports System Imports System.Windows Imports System.Windows.Controls Imports System.Windows.Documents Imports System.Windows.Navigation Imports System.Windows.Shapes Imports System.Windows.Data Imports System.Windows.Media Imports System.Windows.Input Imports wfs = System.Windows.Forms Imports Microsoft.Win32 Namespace VideoBrowser Class MainWindow Inherits Window Public Sub New() InitializeComponent() End Sub ' The list box on the form is ' bound to this variable. Private _thumbnails As New ThumbnailList() Public Property Thumbnails() As ThumbnailList Get Return _thumbnails End Get Set(ByVal value As ThumbnailList) _thumbnails = value End Set End Property Private Sub videoListBox_SelectionChanged( _ ByVal sender As Object, _ ByVal e As SelectionChangedEventArgs) moviePlayer.Close() ' Get the image name: Dim imageName As String = videoListBox.SelectedItem.ToString() ' Find the associated movie: Dim movieName As String = System.IO.Path.ChangeExtension(imageName, "wmv") ' Create a new URI for the selected movie, and play it: moviePlayer.PlayMovie(New Uri(movieName)) End Sub Private Sub selectFolderButton_Click( _ ByVal sender As Object, _ ByVal e As RoutedEventArgs) Dim folderBrowser = New wfs.FolderBrowserDialog() folderBrowser.RootFolder = Environment.SpecialFolder.MyComputer If folderBrowser.ShowDialog() = wfs.DialogResult.OK Then Thumbnails.FolderName = folderBrowser.SelectedPath End If End Sub End Class End Namespace
using System; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Navigation; using System.Windows.Shapes; using System.Windows.Data; using System.Windows.Media; using System.Windows.Input; using wfs = System.Windows.Forms; using Microsoft.Win32; namespace VideoBrowser { /// <summary> /// Interaction logic for Window1.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } // The list box on the form is // bound to this variable. private ThumbnailList _thumbnails = new ThumbnailList(); public ThumbnailList Thumbnails { get { return _thumbnails; } set { _thumbnails = value; } } private void videoListBox_SelectionChanged( object sender, SelectionChangedEventArgs e) { moviePlayer.Close(); // Get the image name: String imageName = videoListBox.SelectedItem.ToString(); // Find the associated movie: string movieName = System.IO.Path. ChangeExtension(imageName, "wmv"); // Create a new URI for the selected movie, and play it: moviePlayer.PlayMovie(new Uri(movieName)); } private void selectFolderButton_Click(object sender, RoutedEventArgs e) { var folderBrowser = new wfs.FolderBrowserDialog(); folderBrowser.RootFolder = Environment.SpecialFolder.MyComputer; if (folderBrowser.ShowDialog() == wfs.DialogResult.OK) { Thumbnails.FolderName = folderBrowser.SelectedPath; } } } }
검사점
이제 응용 프로그램을 빌드하여 실행할 수 있습니다. 폴더 선택... 단추를 누르고 .wmv 및 해당 .jpg 파일이 있는 폴더로 이동합니다. 폴더를 선택하면 .jpg 축소판 그림이 목록 상자에 표시됩니다. 축소판 그림 중 하나를 클릭하면 해당 .wmv 파일이 MediaElement에서 재생됩니다.
응용 프로그램의 스타일 지정
VideoBrowser 응용 프로그램은 기본 스타일로 렌더링됩니다. 직접 만든 스타일을 적용하여 응용 프로그램의 모양과 동작을 변경할 수 있습니다. 스타일은 대개 별도의 리소스 파일에 저장됩니다.
응용 프로그램의 스타일을 지정하려면
솔루션 탐색기에서 새 리소스 사전을 VideoBrowser 프로젝트에 추가합니다. 자세한 내용은 연습: WPF 프로젝트의 리소스 관리를 참조하십시오.
자동으로 생성된 XAML을 다음 XAML로 바꿉니다.
<ResourceDictionary xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"> <!-- Listbox Style --> <Style TargetType="{x:Type ListBox}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ListBox}" > <Border BorderBrush="Gray" BorderThickness="1" CornerRadius="6" Background="{DynamicResource ListBoxGradient}" > <ScrollViewer VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Auto"> <StackPanel IsItemsHost="True" Orientation="Horizontal" HorizontalAlignment="Left" /> </ScrollViewer> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> <!-- Gradients --> <LinearGradientBrush x:Key="ListBoxGradient" StartPoint="0,0" EndPoint="0,1"> <LinearGradientBrush.GradientStops> <GradientStop Color="#90000000" Offset="0" /> <GradientStop Color="#40000000" Offset="0.005" /> <GradientStop Color="#10000000" Offset="0.04" /> <GradientStop Color="#20000000" Offset="0.945" /> <GradientStop Color="#60FFFFFF" Offset="1" /> </LinearGradientBrush.GradientStops> </LinearGradientBrush> <LinearGradientBrush x:Key="VerticalScrollGradient" StartPoint="0,0" EndPoint="1,0"> <LinearGradientBrush.GradientStops> <GradientStop Color="#FDB6CADF" Offset="0" /> <GradientStop Color="#FCC3C5FF" Offset="0.1" /> <GradientStop Color="#FCC4D0EF" Offset="0.3" /> <GradientStop Color="#FDB7C2DF" Offset="0.6" /> <GradientStop Color="#FE95B3CF" Offset="0.8" /> <GradientStop Color="#FE96AACF" Offset="1" /> </LinearGradientBrush.GradientStops> </LinearGradientBrush> <LinearGradientBrush x:Key="WindowGradient" StartPoint="0,0.3" EndPoint="1,0"> <LinearGradientBrush.GradientStops> <GradientStop Color="#B2B6CAFF" Offset="0" /> <GradientStop Color="#BFC3D5FF" Offset="0.1" /> <GradientStop Color="#E0E4F0FF" Offset="0.3" /> <GradientStop Color="#E6EAF5FF" Offset="0.5" /> <GradientStop Color="#CFD7E2FF" Offset="0.6" /> <GradientStop Color="#BFC5D3FF" Offset="0.8" /> <GradientStop Color="#C4CBD8FF" Offset="1" /> </LinearGradientBrush.GradientStops> </LinearGradientBrush> <!-- PHOTOLIST STORYBOARDS --> <Style TargetType="{x:Type ListBoxItem}"> <Setter Property="MaxHeight" Value="100" /> <Setter Property="MinHeight" Value="100" /> <Setter Property="Opacity" Value=".75" /> <Style.Triggers> <EventTrigger RoutedEvent="Mouse.MouseEnter"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard> <DoubleAnimation Duration="0:0:0.2" Storyboard.TargetProperty="MaxHeight" To="110" /> <DoubleAnimation Duration="0:0:0.2" Storyboard.TargetProperty="Opacity" To="1.0" /> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> <EventTrigger RoutedEvent="Mouse.MouseLeave"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard> <DoubleAnimation Duration="0:0:1" Storyboard.TargetProperty="MaxHeight" /> <DoubleAnimation Duration="0:0:0.2" Storyboard.TargetProperty="Opacity" /> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> </Style.Triggers> </Style> <!-- SCROLLBAR TEMPLATES --> <Style x:Key="Scrollbar_LineButton" TargetType="{x:Type RepeatButton}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type RepeatButton}"> <Border BorderBrush="Transparent" BorderThickness="1" CornerRadius="6" Background="{DynamicResource ButtonGradient}"> <ContentPresenter x:Name="ContentSite" /> </Border> </ControlTemplate> </Setter.Value> </Setter> <Setter Property="MinHeight" Value="12" /> <Setter Property="MinWidth" Value="12" /> <Setter Property="Foreground" Value="Gray" /> <Setter Property="FontSize" Value="6pt" /> <Setter Property="FontWeight" Value="Bold" /> <Setter Property="FontFamily" Value="Lucida Sans" /> <Setter Property="VerticalAlignment" Value="Center" /> <Setter Property="HorizontalAlignment" Value="Center" /> </Style> <Style x:Key="ScrollBar_TrackRepeater" TargetType="{x:Type RepeatButton}"> <Setter Property="IsTabStop" Value="false" /> <Setter Property="Focusable" Value="false" /> <Setter Property="Command" Value="ScrollBar.PageUpCommand" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type RepeatButton}"> <Rectangle Fill="Transparent" /> </ControlTemplate> </Setter.Value> </Setter> </Style> <Style x:Key="ScrollBar_UpTrack" BasedOn="{StaticResource ScrollBar_TrackRepeater}" TargetType="{x:Type RepeatButton}"> <Setter Property="Command" Value="ScrollBar.PageUpCommand" /> </Style> <Style x:Key="ScrollBar_DownTrack" BasedOn="{StaticResource ScrollBar_TrackRepeater}" TargetType="{x:Type RepeatButton}"> <Setter Property="Command" Value="ScrollBar.PageDownCommand" /> </Style> <Style x:Key="ScrollBar_LeftTrack" BasedOn="{StaticResource ScrollBar_TrackRepeater}" TargetType="{x:Type RepeatButton}"> <Setter Property="Command" Value="ScrollBar.PageLeftCommand" /> </Style> <Style x:Key="ScrollBar_RightTrack" BasedOn="{StaticResource ScrollBar_TrackRepeater}" TargetType="{x:Type RepeatButton}"> <Setter Property="Command" Value="ScrollBar.PageRightCommand" /> </Style> <Style x:Key="ScrollBar_VerticalThumb" TargetType="{x:Type Thumb}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type Thumb}"> <Border CornerRadius="6" BorderBrush="Transparent" BorderThickness="1" Background="{DynamicResource VerticalScrollGradient}" /> </ControlTemplate> </Setter.Value> </Setter> <Setter Property="MinHeight" Value="10" /> <Setter Property="MinWidth" Value="10" /> </Style> <Style x:Key="ScrollBar_HorizontalThumb" TargetType="{x:Type Thumb}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type Thumb}"> <Border CornerRadius="6" BorderBrush="Transparent" BorderThickness="1" Background="{DynamicResource ButtonGradient}" /> </ControlTemplate> </Setter.Value> </Setter> <Setter Property="MinHeight" Value="10" /> <Setter Property="MinWidth" Value="10" /> </Style> <Style TargetType="{x:Type ScrollBar}"> <Setter Property="Background" Value="Transparent" /> <Setter Property="MinWidth" Value="10" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ScrollBar}"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="10"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="10" /> <RowDefinition Height="*"/> <RowDefinition Height="10" /> </Grid.RowDefinitions> <Border Grid.Row="1" BorderThickness="0" Background="Transparent" CornerRadius="4"/> <RepeatButton Grid.Row="0" Style="{DynamicResource Scrollbar_LineButton}" Command="ScrollBar.LineUpCommand" Content=" ^" /> <Track Grid.Row="1" Name="PART_Track" IsDirectionReversed="True"> <Track.IncreaseRepeatButton> <RepeatButton Style="{DynamicResource ScrollBar_DownTrack}"/> </Track.IncreaseRepeatButton> <Track.DecreaseRepeatButton> <RepeatButton Style="{DynamicResource ScrollBar_UpTrack}"/> </Track.DecreaseRepeatButton> <Track.Thumb> <Thumb Style="{DynamicResource ScrollBar_VerticalThumb}"/> </Track.Thumb> </Track> <RepeatButton Grid.Row="2" Style="{DynamicResource Scrollbar_LineButton}" Command="ScrollBar.LineDownCommand" Content=" v" /> </Grid> </ControlTemplate> </Setter.Value> </Setter> <Style.Triggers> <Trigger Property="Orientation" Value="Horizontal" > <Setter Property="Background" Value="Transparent" /> <Setter Property="MinHeight" Value="10" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ScrollBar}"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="12"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="12" /> <ColumnDefinition Width="*"/> <ColumnDefinition Width="12" /> </Grid.ColumnDefinitions> <Border Grid.Column="1" BorderThickness="0" Background="Transparent" CornerRadius="4"/> <RepeatButton Grid.Column="0" Style="{DynamicResource Scrollbar_LineButton}" Command="ScrollBar.LineLeftCommand" Content=" <" /> <Track Grid.Column="1" Name="PART_Track"> <Track.IncreaseRepeatButton> <RepeatButton Style="{DynamicResource ScrollBar_RightTrack}"/> </Track.IncreaseRepeatButton> <Track.DecreaseRepeatButton> <RepeatButton Style="{DynamicResource ScrollBar_LeftTrack}"/> </Track.DecreaseRepeatButton> <Track.Thumb> <Thumb Style="{DynamicResource ScrollBar_HorizontalThumb}"/> </Track.Thumb> </Track> <RepeatButton Grid.Column="2" Style="{DynamicResource Scrollbar_LineButton}" Command="ScrollBar.LineRightCommand" Content=" >" /> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Trigger> </Style.Triggers> </Style> <Style TargetType="{x:Type Button}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate> <Viewbox x:Name="view" ClipToBounds="False" Stretch="Fill" Width="{TemplateBinding Property=Width}" Height="{TemplateBinding Property=Height}"> <Canvas Width="100" Height ="50" Margin="2"> <Rectangle x:Name="up" Canvas.Top="0" RadiusX="25" RadiusY="25" Width="100" Height="50" Stroke="Black" StrokeThickness="1"> <Rectangle.Fill> <LinearGradientBrush> <LinearGradientBrush.GradientStops> <GradientStop Offset="0" Color="#F53" /> <GradientStop Offset="1" Color="#FAA" /> </LinearGradientBrush.GradientStops> </LinearGradientBrush> </Rectangle.Fill> </Rectangle> <Rectangle x:Name="down" Visibility="Collapsed" Canvas.Top="0" RadiusX="25" RadiusY="25" Width="100" Height="50" Stroke="Black" StrokeThickness="1"> <Rectangle.Fill> <LinearGradientBrush> <LinearGradientBrush.GradientStops> <GradientStop Offset="0" Color="#D88" /> <GradientStop Offset="1" Color="#D31" /> </LinearGradientBrush.GradientStops> </LinearGradientBrush> </Rectangle.Fill> </Rectangle> <Rectangle x:Name="highlight" Canvas.Left="10" Canvas.Top="5" RadiusX="10" RadiusY="10" Width="80" Height="20" StrokeThickness="0"> <Rectangle.Fill> <LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> <LinearGradientBrush.GradientStops> <GradientStop Offset="0" Color="#FFFF" /> <GradientStop Offset="1" Color="#0FFF" /> </LinearGradientBrush.GradientStops> </LinearGradientBrush> </Rectangle.Fill> </Rectangle> <Grid Width="100" Height="50"> <ContentPresenter VerticalAlignment="{TemplateBinding Property=VerticalContentAlignment}" HorizontalAlignment="{TemplateBinding Property=HorizontalContentAlignment}" Content="{TemplateBinding Property=ContentControl.Content}"/> </Grid> </Canvas> </Viewbox> <ControlTemplate.Triggers> <Trigger Property="Button.IsMouseOver" Value="true"> <Setter Property = "Foreground" Value="White"/> </Trigger> <Trigger Property="Button.IsPressed" Value="true"> <Setter TargetName="up" Property="Visibility" Value="Collapsed"/> <Setter TargetName="down" Property="Visibility" Value="Visible"/> <Setter TargetName="highlight" Property="Visibility" Value="Collapsed"/> <Setter Property = "Foreground" Value="Black"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> </ResourceDictionary>
<ResourceDictionary xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"> <!-- Listbox Style --> <Style TargetType="{x:Type ListBox}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ListBox}" > <Border BorderBrush="Gray" BorderThickness="1" CornerRadius="6" Background="{DynamicResource ListBoxGradient}" > <ScrollViewer VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Auto"> <StackPanel IsItemsHost="True" Orientation="Horizontal" HorizontalAlignment="Left" /> </ScrollViewer> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> <!-- Gradients --> <LinearGradientBrush x:Key="ListBoxGradient" StartPoint="0,0" EndPoint="0,1"> <LinearGradientBrush.GradientStops> <GradientStop Color="#90000000" Offset="0" /> <GradientStop Color="#40000000" Offset="0.005" /> <GradientStop Color="#10000000" Offset="0.04" /> <GradientStop Color="#20000000" Offset="0.945" /> <GradientStop Color="#60FFFFFF" Offset="1" /> </LinearGradientBrush.GradientStops> </LinearGradientBrush> <LinearGradientBrush x:Key="VerticalScrollGradient" StartPoint="0,0" EndPoint="1,0"> <LinearGradientBrush.GradientStops> <GradientStop Color="#FDB6CADF" Offset="0" /> <GradientStop Color="#FCC3C5FF" Offset="0.1" /> <GradientStop Color="#FCC4D0EF" Offset="0.3" /> <GradientStop Color="#FDB7C2DF" Offset="0.6" /> <GradientStop Color="#FE95B3CF" Offset="0.8" /> <GradientStop Color="#FE96AACF" Offset="1" /> </LinearGradientBrush.GradientStops> </LinearGradientBrush> <LinearGradientBrush x:Key="WindowGradient" StartPoint="0,0.3" EndPoint="1,0"> <LinearGradientBrush.GradientStops> <GradientStop Color="#B2B6CAFF" Offset="0" /> <GradientStop Color="#BFC3D5FF" Offset="0.1" /> <GradientStop Color="#E0E4F0FF" Offset="0.3" /> <GradientStop Color="#E6EAF5FF" Offset="0.5" /> <GradientStop Color="#CFD7E2FF" Offset="0.6" /> <GradientStop Color="#BFC5D3FF" Offset="0.8" /> <GradientStop Color="#C4CBD8FF" Offset="1" /> </LinearGradientBrush.GradientStops> </LinearGradientBrush> <!-- PHOTOLIST STORYBOARDS --> <Style TargetType="{x:Type ListBoxItem}"> <Setter Property="MaxHeight" Value="100" /> <Setter Property="MinHeight" Value="100" /> <Setter Property="Opacity" Value=".75" /> <Style.Triggers> <EventTrigger RoutedEvent="Mouse.MouseEnter"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard> <DoubleAnimation Duration="0:0:0.2" Storyboard.TargetProperty="MaxHeight" To="110" /> <DoubleAnimation Duration="0:0:0.2" Storyboard.TargetProperty="Opacity" To="1.0" /> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> <EventTrigger RoutedEvent="Mouse.MouseLeave"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard> <DoubleAnimation Duration="0:0:1" Storyboard.TargetProperty="MaxHeight" /> <DoubleAnimation Duration="0:0:0.2" Storyboard.TargetProperty="Opacity" /> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> </Style.Triggers> </Style> <!-- SCROLLBAR TEMPLATES --> <Style x:Key="Scrollbar_LineButton" TargetType="{x:Type RepeatButton}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type RepeatButton}"> <Border BorderBrush="Transparent" BorderThickness="1" CornerRadius="6" Background="{DynamicResource ButtonGradient}"> <ContentPresenter x:Name="ContentSite" /> </Border> </ControlTemplate> </Setter.Value> </Setter> <Setter Property="MinHeight" Value="12" /> <Setter Property="MinWidth" Value="12" /> <Setter Property="Foreground" Value="Gray" /> <Setter Property="FontSize" Value="6pt" /> <Setter Property="FontWeight" Value="Bold" /> <Setter Property="FontFamily" Value="Lucida Sans" /> <Setter Property="VerticalAlignment" Value="Center" /> <Setter Property="HorizontalAlignment" Value="Center" /> </Style> <Style x:Key="ScrollBar_TrackRepeater" TargetType="{x:Type RepeatButton}"> <Setter Property="IsTabStop" Value="false" /> <Setter Property="Focusable" Value="false" /> <Setter Property="Command" Value="ScrollBar.PageUpCommand" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type RepeatButton}"> <Rectangle Fill="Transparent" /> </ControlTemplate> </Setter.Value> </Setter> </Style> <Style x:Key="ScrollBar_UpTrack" BasedOn="{StaticResource ScrollBar_TrackRepeater}" TargetType="{x:Type RepeatButton}"> <Setter Property="Command" Value="ScrollBar.PageUpCommand" /> </Style> <Style x:Key="ScrollBar_DownTrack" BasedOn="{StaticResource ScrollBar_TrackRepeater}" TargetType="{x:Type RepeatButton}"> <Setter Property="Command" Value="ScrollBar.PageDownCommand" /> </Style> <Style x:Key="ScrollBar_LeftTrack" BasedOn="{StaticResource ScrollBar_TrackRepeater}" TargetType="{x:Type RepeatButton}"> <Setter Property="Command" Value="ScrollBar.PageLeftCommand" /> </Style> <Style x:Key="ScrollBar_RightTrack" BasedOn="{StaticResource ScrollBar_TrackRepeater}" TargetType="{x:Type RepeatButton}"> <Setter Property="Command" Value="ScrollBar.PageRightCommand" /> </Style> <Style x:Key="ScrollBar_VerticalThumb" TargetType="{x:Type Thumb}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type Thumb}"> <Border CornerRadius="6" BorderBrush="Transparent" BorderThickness="1" Background="{DynamicResource VerticalScrollGradient}" /> </ControlTemplate> </Setter.Value> </Setter> <Setter Property="MinHeight" Value="10" /> <Setter Property="MinWidth" Value="10" /> </Style> <Style x:Key="ScrollBar_HorizontalThumb" TargetType="{x:Type Thumb}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type Thumb}"> <Border CornerRadius="6" BorderBrush="Transparent" BorderThickness="1" Background="{DynamicResource ButtonGradient}" /> </ControlTemplate> </Setter.Value> </Setter> <Setter Property="MinHeight" Value="10" /> <Setter Property="MinWidth" Value="10" /> </Style> <Style TargetType="{x:Type ScrollBar}"> <Setter Property="Background" Value="Transparent" /> <Setter Property="MinWidth" Value="10" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ScrollBar}"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="10"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="10" /> <RowDefinition Height="*"/> <RowDefinition Height="10" /> </Grid.RowDefinitions> <Border Grid.Row="1" BorderThickness="0" Background="Transparent" CornerRadius="4"/> <RepeatButton Grid.Row="0" Style="{DynamicResource Scrollbar_LineButton}" Command="ScrollBar.LineUpCommand" Content=" ^" /> <Track Grid.Row="1" Name="PART_Track" IsDirectionReversed="True"> <Track.IncreaseRepeatButton> <RepeatButton Style="{DynamicResource ScrollBar_DownTrack}"/> </Track.IncreaseRepeatButton> <Track.DecreaseRepeatButton> <RepeatButton Style="{DynamicResource ScrollBar_UpTrack}"/> </Track.DecreaseRepeatButton> <Track.Thumb> <Thumb Style="{DynamicResource ScrollBar_VerticalThumb}"/> </Track.Thumb> </Track> <RepeatButton Grid.Row="2" Style="{DynamicResource Scrollbar_LineButton}" Command="ScrollBar.LineDownCommand" Content=" v" /> </Grid> </ControlTemplate> </Setter.Value> </Setter> <Style.Triggers> <Trigger Property="Orientation" Value="Horizontal" > <Setter Property="Background" Value="Transparent" /> <Setter Property="MinHeight" Value="10" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ScrollBar}"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="12"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="12" /> <ColumnDefinition Width="*"/> <ColumnDefinition Width="12" /> </Grid.ColumnDefinitions> <Border Grid.Column="1" BorderThickness="0" Background="Transparent" CornerRadius="4"/> <RepeatButton Grid.Column="0" Style="{DynamicResource Scrollbar_LineButton}" Command="ScrollBar.LineLeftCommand" Content=" <" /> <Track Grid.Column="1" Name="PART_Track"> <Track.IncreaseRepeatButton> <RepeatButton Style="{DynamicResource ScrollBar_RightTrack}"/> </Track.IncreaseRepeatButton> <Track.DecreaseRepeatButton> <RepeatButton Style="{DynamicResource ScrollBar_LeftTrack}"/> </Track.DecreaseRepeatButton> <Track.Thumb> <Thumb Style="{DynamicResource ScrollBar_HorizontalThumb}"/> </Track.Thumb> </Track> <RepeatButton Grid.Column="2" Style="{DynamicResource Scrollbar_LineButton}" Command="ScrollBar.LineRightCommand" Content=" >" /> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Trigger> </Style.Triggers> </Style> <Style TargetType="{x:Type Button}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate> <Viewbox x:Name="view" ClipToBounds="False" Stretch="Fill" Width="{TemplateBinding Property=Width}" Height="{TemplateBinding Property=Height}"> <Canvas Width="100" Height ="50" Margin="2"> <Rectangle x:Name="up" Canvas.Top="0" RadiusX="25" RadiusY="25" Width="100" Height="50" Stroke="Black" StrokeThickness="1"> <Rectangle.Fill> <LinearGradientBrush> <LinearGradientBrush.GradientStops> <GradientStop Offset="0" Color="#F53" /> <GradientStop Offset="1" Color="#FAA" /> </LinearGradientBrush.GradientStops> </LinearGradientBrush> </Rectangle.Fill> </Rectangle> <Rectangle x:Name="down" Visibility="Collapsed" Canvas.Top="0" RadiusX="25" RadiusY="25" Width="100" Height="50" Stroke="Black" StrokeThickness="1"> <Rectangle.Fill> <LinearGradientBrush> <LinearGradientBrush.GradientStops> <GradientStop Offset="0" Color="#D88" /> <GradientStop Offset="1" Color="#D31" /> </LinearGradientBrush.GradientStops> </LinearGradientBrush> </Rectangle.Fill> </Rectangle> <Rectangle x:Name="highlight" Canvas.Left="10" Canvas.Top="5" RadiusX="10" RadiusY="10" Width="80" Height="20" StrokeThickness="0"> <Rectangle.Fill> <LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> <LinearGradientBrush.GradientStops> <GradientStop Offset="0" Color="#FFFF" /> <GradientStop Offset="1" Color="#0FFF" /> </LinearGradientBrush.GradientStops> </LinearGradientBrush> </Rectangle.Fill> </Rectangle> <Grid Width="100" Height="50"> <ContentPresenter VerticalAlignment="{TemplateBinding Property=VerticalContentAlignment}" HorizontalAlignment="{TemplateBinding Property=HorizontalContentAlignment}" Content="{TemplateBinding Property=ContentControl.Content}"/> </Grid> </Canvas> </Viewbox> <ControlTemplate.Triggers> <Trigger Property="Button.IsMouseOver" Value="true"> <Setter Property = "Foreground" Value="White"/> </Trigger> <Trigger Property="Button.IsPressed" Value="true"> <Setter TargetName="up" Property="Visibility" Value="Collapsed"/> <Setter TargetName="down" Property="Visibility" Value="Visible"/> <Setter TargetName="highlight" Property="Visibility" Value="Collapsed"/> <Setter Property = "Foreground" Value="Black"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> </ResourceDictionary>
MainWindow.xaml을 열고 MainWindow 요소의 여는 태그 뒤에서 다음 XAML을 주석으로 처리합니다.
<vb:FileToURIConverter x:Key="myConverter" /> <DataTemplate x:Key="imageTemplate"> <Border VerticalAlignment="Center" HorizontalAlignment="Center" Padding="4" Margin="2" Background="White"> <Image Source="{Binding Converter={StaticResource myConverter}}" /> </Border> </DataTemplate>
다음 XAML의 주석 처리를 제거합니다.
<!--<ResourceDictionary > <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="Resources.xaml"/> </ResourceDictionary.MergedDictionaries> <vb:FileToURIConverter x:Key="myConverter" /> <DataTemplate x:Key="imageTemplate"> <Border VerticalAlignment="Center" HorizontalAlignment="Center" Padding="4" Margin="2" Background="White"> <Image Source="{Binding Converter={StaticResource myConverter}}" /> </Border> </DataTemplate> </ResourceDictionary>-->
디자인 뷰를 클릭하여 XAML을 디자인 화면에 로드합니다.
디자인 화면에서 컨트롤에 새 스타일이 적용됩니다.
F5 키를 눌러 응용 프로그램을 빌드 및 실행합니다.