영화 검색앱(TMDB)

sz L·2023년 4월 25일
0

WPF

목록 보기
7/9
post-thumbnail

Google API

Google Developer













※ 네이버 영화 사라짐
Naver Developer


영화진흥위원회

[pw : sujin4792@]

영화진흥위원회

인증키신청


한국영화데이터베이스

한국영화데이터베이스


TMDB

TMDB







Visual Studio





SSMS


MySQL

App.xaml

<Application x:Class="wp11_MovieFinder.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:wp11_MovieFinder"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <!-- MahApps.Metro resource dictionaries. Make sure that all file names are Case Sensitive! -->
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
                <!-- Theme setting -->
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Themes/Light.Emerald.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

MainWindow.xaml

<mah:MetroWindow 
    x:Class="wp11_MovieFinder.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
    xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
    xmlns:local="clr-namespace:wp11_MovieFinder"
    mc:Ignorable="d"
    Title="MovieFinder 2023" Height="450" Width="800" MinHeight="385" MinWidth="645"
    FontFamily="NanumGothic" WindowStartupLocation="CenterScreen" Loaded="MetroWindow_Loaded">
    <mah:MetroWindow.IconTemplate>
        <DataTemplate>
            <iconPacks:PackIconModern Kind="Film" Foreground="White" Margin="5,7,0,0"/>
        </DataTemplate>
    </mah:MetroWindow.IconTemplate>
    <Grid Margin="10">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="2*"/>
            <ColumnDefinition Width="1*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="60"/>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="80"/>
            <RowDefinition Height="1"/>
        </Grid.RowDefinitions>

        <Grid Grid.Row="0" Grid.Column="0" >
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="3*"/>
                <ColumnDefinition Width="1*"/>
            </Grid.ColumnDefinitions>
            
            <!--inputmethod : 커서 위치 검색창, 한글입력 받기 위한 부분-->
            <TextBox  x:Name="TxtMovieName" Grid.Column="0" FontSize="14" Margin="5,10"
                      mah:TextBoxHelper.Watermark="검색할 영화명 입력" 
                      mah:TextBoxHelper.UseFloatingWatermark="True"
                      mah:TextBoxHelper.ClearTextButton="True"
                      InputMethod.PreferredImeState="On"
                      InputMethod.PreferredImeConversionMode="Native" 
                      KeyDown="TxtMovieName_KeyDown"/>
            
            <Button x:Name="BtnSearchMovie" Grid.Column="1" FontSize="14" Margin="5,10"
                    Content="검색" Style="{StaticResource MahApps.Styles.Button.Square.Accent}" Click="BtnSearchMovie_Click">
                <Button.ContentTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <iconPacks:PackIconModern Kind="Magnify" Margin="5"/>
                            <TextBlock Text="{Binding}" Margin="5"/>
                        </StackPanel>
                    </DataTemplate>
                </Button.ContentTemplate>
            </Button>
        </Grid>

        <!--데이터 그리드 영역-->
        <DataGrid Grid.Row="1" Grid.Column="0" x:Name="GrdResult" Margin="5"
                  IsReadOnly="True" Style="{StaticResource MahApps.Styles.DataGrid.Azure}"
                  ItemsSource="{Binding}" AutoGenerateColumns="False" 
                  SelectedCellsChanged="GrdResult_SelectedCellsChanged">
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding Title}" Header="제목" FontWeight="Bold"/>
                <DataGridTextColumn Binding="{Binding Original_Title}" Header="TITLE" />
                <DataGridTextColumn Binding="{Binding Release_Date}" Header="개봉날짜" />
                <DataGridTextColumn Binding="{Binding Popularity, StringFormat={}{0:0.0}}" Header="인지도" >
                    <DataGridTextColumn.ElementStyle>
                        <Style>
                            <Setter Property="TextBlock.TextAlignment" Value="Right"/>
                        </Style>
                    </DataGridTextColumn.ElementStyle>
                </DataGridTextColumn>
                <DataGridTextColumn Binding="{Binding Vote_Average, StringFormat={}{0:0.0}}" Header="평점">
                    <DataGridTextColumn.ElementStyle>
                        <Style>
                            <Setter Property="TextBlock.TextAlignment" Value="Right"/>
                        </Style>
                    </DataGridTextColumn.ElementStyle>
                </DataGridTextColumn>
                <!--<DataGridCheckBoxColumn Binding="{Binding Adult}" Header="성인물" />-->
            </DataGrid.Columns>
        </DataGrid>
        
        <!--포스터 영역-->
        <Grid Grid.Row="0" Grid.Column="1" Grid.RowSpan="2">
            <GroupBox Header="포스터" Margin="5"
                      mah:HeaderedControlHelper.HeaderFontSize="14"
                      mah:HeaderedControlHelper.HeaderHorizontalContentAlignment="Center"
                      mah:HeaderedControlHelper.HeaderFontFamily="NanumGothic"
                      mah:HeaderedControlHelper.HeaderFontWeight="Bold">
                <Image x:Name="ImgPoster" Source="No_Picture.png" Margin="15,5" />
            </GroupBox>
        </Grid>
        
        <!--#region버튼-->
        <StackPanel Grid.Column="0" Grid.Row="2" Grid.ColumnSpan="2" Orientation="Horizontal" >
            <Button x:Name="BtnAddFavorite" Content="즐겨찾기 추가" Margin="5,20" FontSize="12" 
                    Style="{StaticResource MahApps.Styles.Button.Square.Accent}" Click="BtnAddFavorite_Click">
                <Button.ContentTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <iconPacks:PackIconModern Kind="ListAdd" Margin="5,5"/>
                            <TextBlock Text="{Binding}" Margin="5"/>
                        </StackPanel>
                    </DataTemplate>
                </Button.ContentTemplate>
            </Button>

            <Button x:Name="BtnViewFavorite" Content="즐겨찾기 보기" Margin="5,20" FontSize="12" 
                    Style="{StaticResource MahApps.Styles.Button.Square.Highlight}" Click="BtnViewFavorite_Click">
                <Button.ContentTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <iconPacks:PackIconModern Kind="List" Margin="5,5"/>
                            <TextBlock Text="{Binding}" Margin="5"/>
                        </StackPanel>
                    </DataTemplate>
                </Button.ContentTemplate>
            </Button>

            <Button x:Name="BtnDelFavorite" Content="즐겨찾기 삭제" Margin="5,20" FontSize="12" 
                    Style="{StaticResource MahApps.Styles.Button.Square}" Click="BtnDelFavorite_Click">
                <Button.ContentTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <iconPacks:PackIconModern Kind="ListDelete" Margin="5,5" Foreground="#099A46"/>
                            <TextBlock Text="{Binding}" Margin="5"/>
                        </StackPanel>
                    </DataTemplate>
                </Button.ContentTemplate>
            </Button>

            <Button x:Name="BtnWatchTrailer" Content="예고편 보기" Margin="5,20" FontSize="12" 
                    Style="{StaticResource MahApps.Styles.Button.Flat}" Click="BtnWatchTrailer_Click">
                <Button.ContentTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <iconPacks:PackIconModern Kind="YoutubePlay" Margin="5,5" Foreground="#E7161B"/>
                            <TextBlock Text="{Binding}" Margin="5"/>
                        </StackPanel>
                    </DataTemplate>
                </Button.ContentTemplate>
            </Button>

            <!--<Button x:Name="BtnNaverMovie" Content="네이버 영화" Margin="5,20" FontSize="12" 
                    Style="{StaticResource MahApps.Styles.Button.Flat}" Click="BtnNaverMovie_Click">
                <Button.ContentTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <Image Source="Naverlogo.png" Width="15" Margin="5,5"/>
                            <TextBlock Text="{Binding}" Margin="5"/>
                        </StackPanel>
                    </DataTemplate>
                </Button.ContentTemplate>
            </Button>-->
        </StackPanel>
        <!--#endregion-->
        
        <!--상태표시바-->
        <StatusBar Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" Margin="-10">
            <StatusBarItem Content="TMDB &amp; Youtube OpenAPI App"/>
            <Separator Style="{StaticResource MahApps.Styles.Separator.StatusBar}"/>
            <StatusBarItem x:Name="StsResult"/>
        </StatusBar>
    </Grid>
</mah:MetroWindow>

MainWindow.xaml.cs

using ControlzEx.Standard;
using MahApps.Metro.Controls;
using MySql.Data.MySqlClient;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using wp11_MovieFinder.Logics;
using wp11_MovieFinder.Models;

namespace wp11_MovieFinder
{
    /// <summary>
    /// MainWindow.xaml에 대한 상호 작용 논리
    /// </summary>
    public partial class MainWindow : MetroWindow
    {
        bool isFavorite = false;    // false -> 
        public MainWindow()
        {
            InitializeComponent();
        }

        private async void BtnNaverMovie_Click(object sender, RoutedEventArgs e)
        {
            await Commons.ShowMessageAsync("네이버영화", "네이버영화 사이트로 갑니다.");
        }

        // 검색버튼, 네이버API 영화 검색
        private async void BtnSearchMovie_Click(object sender, RoutedEventArgs e)
        {
            if (string.IsNullOrEmpty(TxtMovieName.Text))
            {
                await Commons.ShowMessageAsync("검색", "검색할 영화명을 입력하세요.");
                return;
            }
            //if (TxtMovieName.Text.Length < 2)
            //{
            //    await Commons.ShowMessageAsync("검색", "검색어를 두글자 이상 입력하세요.");
            //    return;
            //}

            try
            {
                SearchMovie(TxtMovieName.Text);
            }
            catch (Exception ex)
            {
                await Commons.ShowMessageAsync("오류", $"오류발생 : {ex.Message}");
            }
        }

        // 텍스트박스에서 키를 입력할때 엔터를 누르면 검색 시작
        private void TxtMovieName_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                BtnSearchMovie_Click(sender, e);
            }
        }
        // 실제 검색 메서드
        private async void SearchMovie(string movieName)
        {
            string tmdb_apiKey = "fd2b7822a5956759efbe476287b3a0c0";
            string encording_movieName = HttpUtility.UrlDecode(movieName, Encoding.UTF8);
            string openApiUri = $@"https://api.themoviedb.org/3/search/movie?api_key={tmdb_apiKey}" +
                                $"&language=ko-KR&page=1&include_adult=false&query={encording_movieName}";
            string result = string.Empty;       //결과값

            //api 실행할 객체
            WebRequest req = null;
            WebResponse res = null;
            StreamReader reader = null;

            // TMDB API 요청
            try
            {
                req = WebRequest.Create(openApiUri);        // Url을 넣어서 객체를 생성
                res = await req.GetResponseAsync();    // 요청한 결과를 비동기 응답에 할당 .. 비동기로 동작하는 버튼
                reader = new StreamReader(res.GetResponseStream()); 
                result = reader.ReadToEnd();        // json 결과 텍스트로 저장

                Debug.WriteLine(result);
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                reader.Close();
                res.Close();
            }

            //result를 json으로 변경
            var jsonResult = JObject.Parse(result); // string -> json

            var total = Convert.ToInt32(jsonResult["total_results"]);   //전체 검색결과 수
            //await Commons.ShowMessageAsync("검색결과", total.ToString());

            var items = jsonResult["results"];
            // items를 데이터그리드에 표시
            var json_array = items as JArray;

            var movieItems = new List<MovieItem>();     // json에서 넘어온 배열을 담을 장소
            foreach (var val in json_array)
            {
                var MovieItem = new MovieItem()
                {
                    Adult = Convert.ToBoolean(val["adult"]),
                    Id = Convert.ToInt32(val["id"]),
                    Original_Language = Convert.ToString(val["original_language"]),
                    Original_Title = Convert.ToString(val["original_title"]),
                    Overview = Convert.ToString(val["overview"]),
                    Popularity = Convert.ToDouble(val["popularity"]),
                    Poster_Path = Convert.ToString(val["poster_path"]),
                    Release_Date = Convert.ToString(val["release_date"]),
                    Title = Convert.ToString(val["title"]),
                    Vote_Average = Convert.ToDouble(val["vote_average"])
                };
                movieItems.Add(MovieItem);
            }
            this.DataContext = movieItems;
            isFavorite = false;     //즐겨찾기 아님

            StsResult.Content = $"OpenAPI {movieItems.Count}건 조회완료";
        }

        private void MetroWindow_Loaded(object sender, RoutedEventArgs e)
        {
            TxtMovieName.Focus();   // 텍스트 박스에 포커스 set
        }

        // 그리드에서 셀을 선택하면 발생하는 이벤트 핸들러
        private async void GrdResult_SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e)
        {
            try
            {
                string posterPath = string.Empty;
                if(GrdResult.SelectedItem is MovieItem)     // OpenAPI로 검색된 영화의 포스터
                {
                    var movie = GrdResult.SelectedItem as MovieItem;
                    posterPath = movie.Poster_Path;
                }
                else if(GrdResult.SelectedItem is FavoriteMovieItem)        // 즐겨찾기 DB에서 가져온 영화 포스터
                {
                    var movie = GrdResult.SelectedItem as FavoriteMovieItem;
                    posterPath = movie.Poster_Path;
                }


                Debug.WriteLine(posterPath);
                if(string.IsNullOrEmpty(posterPath)) // 포스터 이미지가 없다면 => No_Picture 나오게
                {
                    ImgPoster.Source = new BitmapImage(new Uri("/No_Picture.png", UriKind.RelativeOrAbsolute));
                }
                else        // 포스터 이미지 경로가 존재한다면
                {
                    var base_url = "https://www.themoviedb.org/t/p/w600_and_h900_bestv2";
                    ImgPoster.Source = new BitmapImage(new Uri($"{base_url}{posterPath}", UriKind.RelativeOrAbsolute));
                }
            }
            catch
            {
                await Commons.ShowMessageAsync("오류", $"이미지로드 오류발생");
            }
        }

        // 영화 예고편 유튜브에서 보기
        private async void BtnWatchTrailer_Click(object sender, RoutedEventArgs e)
        {
            if(GrdResult.SelectedItems.Count == 0)
            {
                await Commons.ShowMessageAsync("유튜브", "영화를 선택하세요.");
                return;
            }

            if(GrdResult.SelectedItems.Count > 1) 
            {
                await Commons.ShowMessageAsync("유튜브", "영화를 하나만 선택하세요.");
                return;
            }

            string movieName = string.Empty;
            // 전체 넘기는 코드 가져오기
            if(GrdResult.SelectedItem is MovieItem)
            {
                var movie = GrdResult.SelectedItem as MovieItem;
                movieName = movie.Title;
            }
            else if(GrdResult.SelectedItem is FavoriteMovieItem)
            {
                var movie = GrdResult.SelectedItem as FavoriteMovieItem;
                movieName = movie.Title;
            }

            //movieName = (GrdResult.SelectedItem as MovieItem).Title;
            //await Commons.ShowMessageAsync("유튜브", $"예고편 볼 영화 {movieName}");
            var trailerWindow = new TrailerWindow(movieName);
            trailerWindow.Owner = this;     //TrailerWindow의 부모는 MainWindow
            trailerWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner;    // 부모창의 정중앙에 위치
            //trailerWindow.Show();       // 모달리스로 창을 열면 부모창 접근 가능 
            trailerWindow.ShowDialog();   // 모달창
        }

        //즐겨찾기 추가
        private async void BtnAddFavorite_Click(object sender, RoutedEventArgs e)
        {
            if(GrdResult.SelectedItems.Count ==0)
            {
                await Commons.ShowMessageAsync("오류", "즐겨찾기에 추가할 영화를 선택하세요.(복수선택 가능)");
                return;
            }

            if(isFavorite )
            {
                await Commons.ShowMessageAsync("오류", "이미 즐겨찾기한 오류입니다.");
                return;
            }



            /*   리스트 안만들어도 됨
             List<FavoriteMovieItem> list = new List<FavoriteMovieItem>();
            foreach (MovieItem item in GrdResult.SelectedItems)
            {
                var favoriteMovie = new FavoriteMovieItem
                {
                    Id = item.Id,
                    Title = item.Title,
                    Original_Title = item.Original_Title,
                    Original_Language = item.Original_Language,
                    Adult = item.Adult,
                    Overview = item.Overview,
                    Release_Date = item.Release_Date,
                    Vote_Average = item.Vote_Average,
                    Popularity = item.Popularity,
                    Poster_Path = item.Poster_Path,
                    Reg_Date = DateTime.Now     // 지금 저장하는 일시
                };
                list.Add(favoriteMovie);
            }*/

            #region < MySQL DB 데이터 입력(Test)>
            /*try
            {
                // DB 
                using (MySqlConnection conn = new MySqlConnection(Commons.myConnString))
                {
                    if (conn.State == ConnectionState.Closed) conn.Open();
                    var query = @"INSERT INTO FavoriteMovieItem
                                              ( Id
                                              , Title
                                              , Original_Title
                                              , Release_Date
                                              , Original_Language
                                              , Adult
                                              , Popularity
                                              , Vote_Average
                                              , Poster_Path
                                              , Overview
                                              , Reg_Date )
                                         VALUES
                                              ( @Id
                                              , @Title
                                              , @Original_Title
                                              , @Release_Date
                                              , @Original_Language
                                              , @Adult
                                              , @Popularity
                                              , @Vote_Average
                                              , @Poster_Path
                                              , @Overview
                                              , @Reg_Date )";

                    var insRes = 0;
                    foreach (FavoriteMovieItem item in list)
                    {
                        MySqlCommand cmd = new MySqlCommand(query, conn);
                        cmd.Parameters.AddWithValue("@Id", item.Id);
                        cmd.Parameters.AddWithValue("@Title", item.Title);
                        cmd.Parameters.AddWithValue("@Original_Title", item.Original_Title);
                        cmd.Parameters.AddWithValue("@Release_Date", item.Release_Date);
                        cmd.Parameters.AddWithValue("@Original_Language", item.Original_Language);
                        cmd.Parameters.AddWithValue("@Adult", item.Adult);
                        cmd.Parameters.AddWithValue("@Popularity", item.Popularity);
                        cmd.Parameters.AddWithValue("@Vote_Average", item.Vote_Average);
                        cmd.Parameters.AddWithValue("@Poster_Path", item.Poster_Path);
                        cmd.Parameters.AddWithValue("@Overview", item.Overview);
                        cmd.Parameters.AddWithValue("@Reg_Date", item.Reg_Date);

                        insRes += cmd.ExecuteNonQuery();
                    }
                }
            }
            catch (Exception ex)
            {
                await Commons.ShowMessageAsync("오류", $"DB저장 오류 {ex.Message}");
            }*/
            #endregion

            #region < SQL Server DB 데이터 입력>
            try
            {
                // DB 
                using (SqlConnection conn = new SqlConnection(Commons.connString))
                {
                    if(conn.State == ConnectionState.Closed) conn.Open();
                    var query = @"INSERT INTO [dbo].[FavoriteMovieItem]
                                              ( [Id]
                                              , [Title]
                                              , [Original_Title]
                                              , [Release_Date]
                                              , [Original_Language]
                                              , [Adult]
                                              , [Popularity]
                                              , [Vote_Average]
                                              , [Poster_Path]
                                              , [Overview]
                                              , [Reg_Date] )
                                         VALUES
                                              ( @Id
                                              , @Title
                                              , @Original_Title
                                              , @Release_Date
                                              , @Original_Language
                                              , @Adult
                                              , @Popularity
                                              , @Vote_Average
                                              , @Poster_Path
                                              , @Overview
                                              , @Reg_Date )";

                    var insRes = 0;
                    foreach (MovieItem item in GrdResult.SelectedItems)     // OpenAPI로 검색된 결과라서 MovieItem
                    {
                        SqlCommand cmd = new SqlCommand(query, conn);
                        cmd.Parameters.AddWithValue("@Id",item.Id);
                        cmd.Parameters.AddWithValue("@Title", item.Title);
                        cmd.Parameters.AddWithValue("@Original_Title", item.Original_Title);
                        cmd.Parameters.AddWithValue("@Release_Date", item.Release_Date);
                        cmd.Parameters.AddWithValue("@Original_Language", item.Original_Language);
                        cmd.Parameters.AddWithValue("@Adult", item.Adult);
                        cmd.Parameters.AddWithValue("@Popularity", item.Popularity);
                        cmd.Parameters.AddWithValue("@Vote_Average", item.Vote_Average);
                        cmd.Parameters.AddWithValue("@Poster_Path", item.Poster_Path);
                        cmd.Parameters.AddWithValue("@Overview", item.Overview);
                        cmd.Parameters.AddWithValue("@Reg_Date", DateTime.Now);

                        insRes += cmd.ExecuteNonQuery();
                    }
                    if(GrdResult.SelectedItems.Count == insRes)
                    {
                        await Commons.ShowMessageAsync("저장", "즐겨찾기 추가 성공");
                        StsResult.Content = $"즐겨찾기 {insRes}건 저장완료";

                    }
                    else
                    {
                        await Commons.ShowMessageAsync("저장", "즐겨찾기 추가 실패! 관리자에게 문의하세요.");
                    }
                }
            }
            catch (Exception ex)
            {
                await Commons.ShowMessageAsync("오류",$"DB저장 오류 {ex.Message}");
            }
            #endregion
        }

        // 즐겨찾기 보기
        private async void BtnViewFavorite_Click(object sender, RoutedEventArgs e)
        {
            this.DataContext = null;
            TxtMovieName.Text = string.Empty;

            List<FavoriteMovieItem> list = new List<FavoriteMovieItem>();
            try
            {
                using (SqlConnection conn = new SqlConnection(Commons.connString))
                {
                    if(conn.State == ConnectionState.Closed) conn.Open();

                    var query = @"SELECT Id
                                      ,Title
                                      ,Original_Title
                                      ,Release_Date
                                      ,Original_Language
                                      ,Adult
                                      ,Popularity
                                      ,Vote_Average
                                      ,Poster_Path
                                      ,Overview
                                      ,Reg_Date
                                  FROM FavoriteMovieItem
                                 ORDER BY Id ASC";
                    var cmd = new SqlCommand(query, conn);
                    var adapter = new SqlDataAdapter(cmd);
                    var dSet = new DataSet();
                    adapter.Fill(dSet, "FavoriteMovieItem");
                    
                    foreach (DataRow dr in dSet.Tables["FavoriteMovieItem"].Rows) {
                        list.Add(new FavoriteMovieItem
                        {
                            Id = Convert.ToInt32(dr["id"]),
                            Title = Convert.ToString(dr["title"]),
                            Original_Title = Convert.ToString(dr["Original_Title"]),
                            Release_Date = Convert.ToString(dr["Release_Date"]),
                            Original_Language = Convert.ToString(dr["Original_Language"]),
                            Adult = Convert.ToBoolean(dr["Adult"]),
                            Popularity = Convert.ToDouble(dr["Popularity"]),
                            Vote_Average = Convert.ToDouble(dr["Vote_Average"]),
                            Poster_Path = Convert.ToString(dr["Poster_Path"]),
                            Overview = Convert.ToString(dr["Poster_Path"]),
                            Reg_Date = Convert.ToDateTime(dr["Reg_Date"])
                        });
                    }
                    this.DataContext = list;
                    isFavorite = true;
                    StsResult.Content = $"즐겨찾기 {list.Count}건 조회완료";
                }
            }
            catch (Exception ex) 
            {
                await Commons.ShowMessageAsync("오류", $"DB조회 오류 {ex.Message}");
            }
        }

        // 즐겨찾기 삭제
        private async void BtnDelFavorite_Click(object sender, RoutedEventArgs e)
        {
            if(isFavorite == false)
            {
                await Commons.ShowMessageAsync("오류", "즐겨찾기만 삭제할 수 있습니다.");
                return;
            }
            if(GrdResult.SelectedItems.Count == 0)
            {
                await Commons.ShowMessageAsync("오류", "삭제할 영화를 선택하세요");
                return;
            }
            try         // 삭제
            {
                using (SqlConnection conn = new SqlConnection(Commons.connString))
                {
                    if (conn.State == ConnectionState.Closed) conn.Open();

                    var query = "DELETE FROM FavoriteMovieItem WHERE Id = @Id";
                    var delRes = 0;

                    foreach (FavoriteMovieItem item in GrdResult.SelectedItems)
                    {
                        SqlCommand cmd = new SqlCommand(query, conn);
                        cmd.Parameters.AddWithValue("@Id", item.Id);

                        delRes += cmd.ExecuteNonQuery();
                    }
                    if(delRes == GrdResult.SelectedItems.Count)
                    {
                        await Commons.ShowMessageAsync("삭제", "DB삭제 성공!");
                        BtnViewFavorite_Click(sender, e);       //즐겨찾기 보기 이벤트 핸들러 한 번 실행
                        StsResult.Content = $"즐겨찾기 {delRes}건 삭제완료";     //  바로 즐겨찾기 조회창이 뜨기 때문에 화면에서 볼 수 없다
                    }
                    else
                    {
                        await Commons.ShowMessageAsync("삭제", "DB삭제 일부 성공"); //발생 가능성 낮음
                    }
                }
            }
            catch (Exception ex)
            {
                await Commons.ShowMessageAsync("오류",$"DB삭제오류 {ex.Message}");
            }
        }
    }
}

Models

MovieItem.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace wp11_MovieFinder.Models
{
    public class MovieItem
    {
        public bool Adult { get; set; }
        public int Id { get; set; }
        public string Original_Language { get; set; }
        public string Original_Title { get; set;}
        public string Overview { get; set; }
        public double Popularity { get; set; }  
        public string Poster_Path { get; set; }
        public string Release_Date { get; set; }
        public string Title { get; set; }
        public double Vote_Average { get; set; }
    }
}

FavoriteMovieItem.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace wp11_MovieFinder.Models
{
    internal class FavoriteMovieItem
    {
        public bool Adult { get; set; }

        public int Id { get; set; }
        public string Original_Language { get; set; }
        public string Original_Title { get; set; }
        public string Overview { get; set; }
        public double Popularity { get; set; }
        public string Poster_Path { get; set; }
        public string Release_Date { get; set; }
        public string Title { get; set; }
        public double Vote_Average { get; set; }
        public DateTime Reg_Date { get; set; }
    }
}

YoutubeItem.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media.Imaging;

namespace wp11_MovieFinder.Models
{
    internal class YoutubeItem
    {
        public string Title { get; set; }
        public string Author { get; set; }
        public string URL { get; set; }
        public string ChannelTitle { get; set; }
        public BitmapImage Thumbnail { get; set; }
    }
}

Logics

Commons.cs

using Google.Protobuf.WellKnownTypes;
using MahApps.Metro.Controls;
using MahApps.Metro.Controls.Dialogs;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace wp11_MovieFinder.Logics
{
    public class Commons
    {
        // 연결문자열 담을 변수
        // SQL Server용
        public static readonly string connString = "Data Source=localhost;" +
                                                   "Initial Catalog=pknu;" +
                                                   "Persist Security Info=True;" +
                                                   "User ID=sa;" +
                                                   "Password=12345";

        // MySQL용
        public static readonly string myConnString = "Server=localhost;" +
                                                     "Port=3306;" +
                                                     "Database=miniproject;" +
                                                     "Uid=root;" +
                                                     "Pwd=815301;";


        // 매트로 다이얼로그창을 위한 정적 메서드
        public static async Task<MessageDialogResult> ShowMessageAsync(string title, string message, 
            MessageDialogStyle style = MessageDialogStyle.Affirmative)
        {
            return await ((MetroWindow)Application.Current.MainWindow).ShowMessageAsync(title, message, style, null);
        }
    }
}

창 추가

TrailerWindow.xaml

<mah:MetroWindow 
    x:Class="wp11_MovieFinder.TrailerWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
    xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
    xmlns:cefSharp="clr-namespace:CefSharp.Wpf;assembly=CefSharp.Wpf"
    xmlns:local="clr-namespace:wp11_MovieFinder"
    mc:Ignorable="d"
    Title="유튜브 예고편" Height="350" Width="800" FontFamily="NanumGothic" Loaded="MetroWindow_Loaded"
    Closing="MetroWindow_Closing">
    <mah:MetroWindow.IconTemplate>
        <DataTemplate>
            <iconPacks:PackIconModern Kind="Youtube" Foreground="White" Margin="5,7,0,0"/>
        </DataTemplate>
    </mah:MetroWindow.IconTemplate>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*"/>
            <ColumnDefinition Width="1*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="50"/>
            <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>

        <Label Grid.Row="0" Grid.Column="0" x:Name="LblMovieName" FontSize="14" Margin="10"/>

        <ListView Grid.Row="1" Grid.Column="0" x:Name="LsvResult" Margin="5" MouseDoubleClick="LsvResult_MouseDoubleClick" >
            <ListView.View>
                <GridView>
                    <!--컬럼들을 나열-->
                    <GridViewColumn Header="썸네일" Width="100">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <Image Source="{Binding Thumbnail}"/>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>

                    <GridViewColumn Header="타이틀" Width="Auto"
                                    DisplayMemberBinding="{Binding Title}"/>

                    <!--<GridViewColumn Header="제작자" Width="Auto"
                                    DisplayMemberBinding="{Binding Author}"/>-->

                    <GridViewColumn Header="채널명" Width="Auto"
                                    DisplayMemberBinding="{Binding ChannelTitle}"/>

                    <GridViewColumn Header="링크" Width="Auto"
                                    DisplayMemberBinding="{Binding URL}"/>
                </GridView>
            </ListView.View>
        </ListView>
        
        <!--웹브라우저 영역-->
        <Grid Grid.Row="0" Grid.Column="1" Grid.RowSpan="2" Margin="10" Background="LightGray">
            <!--<WebBrowser/> 문제 많음-->
            <cefSharp:ChromiumWebBrowser x:Name="BrsYoutube" Address="https://www.youtube.com"/>
        </Grid>
    </Grid>
</mah:MetroWindow>

TrailerWindow.xaml.cs

using CefSharp.DevTools.WebAudio;
using Google.Apis.Services;
using Google.Apis.YouTube.v3;
using Google.Apis.YouTube.v3.Data;
using MahApps.Metro.Controls;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using wp11_MovieFinder.Models;

namespace wp11_MovieFinder
{
    /// <summary>
    /// TrailerWindow.xaml에 대한 상호 작용 논리
    /// </summary>
    public partial class TrailerWindow : MetroWindow
    {
        List<YoutubeItem> youtubeItems = null;      //검색결과 담을 리스트
        public TrailerWindow()
        {
            InitializeComponent();
        }

        // 부모에서 데이터를 가져오려면 재정의 생성자 만들어야함
        public TrailerWindow(string movieName) : this()
        {
            LblMovieName.Content = $"{movieName} 예고편";
        }

        // 부모에서 객체를 통채로 가져오기 가능
        public TrailerWindow(MovieItem movie) : this()
        {
            LblMovieName.Content = $"{movie.Title} 예고편";
        }

        //화면 로드 완료후에 YouTubeAPI 실행
        private void MetroWindow_Loaded(object sender, RoutedEventArgs e)
        {
            youtubeItems = new List<YoutubeItem>();     //초기화
            SearchYoutubeApi();
        }

        private async void SearchYoutubeApi()
        {
            await LoadDataCollection();
            LsvResult.ItemsSource = youtubeItems;
        }

        private async Task LoadDataCollection()
        {
            var youtubeService = new YouTubeService(
                new BaseClientService.Initializer()
                {
                    ApiKey = "AIzaSyBFgCk2MCu91cEjgZJdu8eqQjNYjJKCx8c",
                    ApplicationName = this.GetType().ToString()
                }
                );
            var req = youtubeService.Search.List("snippet");
            req.Q = LblMovieName.Content.ToString();
            req.MaxResults = 10;

            var res = await req.ExecuteAsync();         //검색결과 가져옴

            Debug.WriteLine("-------------------유튜브 검색결과-------------------");
            foreach ( var item in res.Items )
            {
                Debug.WriteLine(item.Snippet.Title);
                if(item.Id.Kind.Equals("youtube#video"))
                {
                    YoutubeItem youtube = new YoutubeItem()
                    {
                        Title = item.Snippet.Title,
                        ChannelTitle = item.Snippet.ChannelTitle,
                        URL = $"https://www.youtube.com/watch?v={item.Id.VideoId}",
                        //Author = item.Snippet.ChannelTitle
                    };
                    youtube.Thumbnail = new BitmapImage(new Uri(item.Snippet.Thumbnails.Default__.Url,
                                                                    UriKind.RelativeOrAbsolute));
                    youtubeItems.Add(youtube);  
                }
            }
        }

        private void LsvResult_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            if(LsvResult.SelectedItem is YoutubeItem)
            {
                var video = LsvResult.SelectedItem as YoutubeItem;
                BrsYoutube.Address = video.URL;
            }
        }

        private void MetroWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            BrsYoutube.Address = string.Empty;  //웹브라우저 주소 클리어
            BrsYoutube.Dispose();       // 리소스 해제(!)
        }
    }
}


실행결과

profile
가랑비는 맞는다 하지만 폭풍은 내 것이야

0개의 댓글