砂漠の旅人(たびと)

UNIX / MS-DOS 時代から電脳砂漠を旅しています

【C#】YouTube からビデオとオーディオをダウンロードするアプリを作ってみる - その2

こんにちは、たびとです。

前回は、お手軽 YouTube ダウンローダーの中核部分を説明しました。 その後、ダウンロード処理と並行して画面周りを作りこんでいます。

現在、画面周りを作りこんでいますが、WPF の画面では味気ないため、 今どきのマテリアルデザインにしてしようと思ったのが運の尽きでした。

有名どころの MahApps と MaterialDesign Xaml Toolkit があるのですが、 これを合わせて使うのが流行り(普通?)らしいですが、初心者には壁が高過ぎですね。 先週から、あれこれ悩みながら画面を「 作っては壊して 」の繰り返しで、 少しずつ画面を作り込んでいます。

ということで、今回は おしゃれ画面 の苦労話が中心です。

この記事の対象者

  • YouTube からビデオをダウンロードすることに興味のある方
  • C#マテリアルデザインのアプリケーションを作ってみたい方
  • MahApps と MaterialDesign Xaml Toolkit に興味のある方

前回のおさらい

前回は、YouTube からダウンロードするライブラリとダウンロードした オーディオファイル(AAC)をMP3にコンバートするところまでを説明しました。

sabakunotabito.hatenablog.com

コンバートして MP3 を作るところまでは良かったのですが、 ビットレートが変更されるため、コンバート後にどれぐらいになったのかを 把握しておく必要があります。

また、MP3 はコンバートして作るため、YouTube のタイトルがないため、 これを書き込む必要があります。

この2つを満たすライブラリを NuGet で探したところ、 mono / taglib-sharp というライブラリが見つかりました。

github.com

このライブラリは、同じ名前でもう一つあるんですが、 どっちも同じような内容なので、こちらにしました。

mono / taglib-sharp のサンプル

以下、GitHub のサンプルをビットレートに変更したものですが、 使い方は、とても簡単です。

var tfile = TagLib.File.Create(@"C:\My audio.mp3");
var bitrate = tfile.Properties.AudioBitrate;      // ビットレート取得 
tfile.Tag.Title = "YouTube のタイトル";
tfile.Save();

これも、NAudio と同様に非同期はないようなので、 GUI で作る場合は、Task.Run() を使うことになりそうですね。

マテリアルデザインWPF

MahApps と MaterialDesign Xaml Toolkit って、 NuGet で検索すると、大量にヒットするんですが、 どれを選べば良いのか、そこから迷います。

とりあえず、やってみよう

インターネットで色々と調べてみたところ、 MahApps を中心に NuGet からダウンロードしてみました。 インストールしたのは、以下の 4 つです。

  • MahApps.Metro 2.4.9
  • MahApps.Metro.IconPacks 4.11.0
  • MaterialDesignInXamlToolkit 0.2.0
  • Orchestra.Shell.MahApps 6.6.6

まずは、App.xaml の Application.Resources にお決まりのおまじないを追加します。 後は MainWindow.xaml の先頭を Window から mah:MetroWindow に変更し、 MainWindow.xaml.cs の方も Window を MahApps.Metro.Controls.MetroWindow に変更します。 この辺の基本的な情報は、少し探せばすぐに手に入るので割愛します。

メイン画面を作り上げる

マニュアルとの激闘の末、何度も作り直しながら、何とか画面が完成しました。 デフォルトが紫なので、今はそのままの色を使っています。

マテリアルデザインで開発中の画面
マテリアルデザインで開発中

アプリの名前は「YouTube をおなか一杯食べよう」とのコンセプトから、 「TubeEater」と名付けてみました。 昔、たびとが夢中で遊んだ「MGS3 SNAKE EATER」から拝借した訳ではありません。

さて、通常の WPF との違いは、ToolBarTray を materialDesign:ColorZone に変更したことです。 GitHub マークは mah:MetroWindow.RightWindowCommands を使っています。 この辺りも、インターネットで調べればすぐに理解できると思います。

ここで、難解なのは左上の横3本線アイコンの ハンバーガ トグルボタンです。 メニューボタンを押すと、左からメニューが表示され、このときメイン画面は暗くなって操作できなくなります。 元に戻るには、メニューボタンかメイン画面の暗い箇所をクリックします。

実装には、 materialDesign:DrawerHost を使いますが、インターネットで調べても これをどこに配置すれば良いのかが、全く理解できませんでした。

この DrawerHost は画面全体を表すもの、と考えるといいかもしれません。 この中に、materialDesign:DrawerHost.LeftDrawerContent を使って、左から出現するメニューを定義し、 残りを DockPanel などの中に記載します。 DockPanel の中は、メニューの ColorZone と本体の DataGrid を配置します。

このとき、メニューの出し入れは、ColorZone 内のトグルボタンのオン・オフで制御するため、 この紐づけを DrawerHost と DrawerHost.LeftDrawerContent にそれぞれ記載します。

このハンバーガーに特化して記載すると以下のようになります。

<mah:MetroWindow
 <!-- 中略 -->
    mc:Ignorable="d">
<materialDesign:DrawerHost x:Name="drawerHostMain" IsLeftDrawerOpen="{Binding ElementName=toggleButtonMenu, Path=IsChecked}">
    <materialDesign:DrawerHost.LeftDrawerContent>
        <DockPanel MinWidth="220">
            <!-- 左メニューのハンバーガー制御 -->
            <ToggleButton
                Margin="8,16,8,0"
                HorizontalAlignment="Right"
                DockPanel.Dock="Top"
                IsChecked="{Binding ElementName=toggleButtonMenu, Path=IsChecked, Mode=TwoWay}"
                Style="{StaticResource MaterialDesignHamburgerToggleButton}" />

            <!-- 好きな左メニュー項目を配置する -->

        </DockPanel>
    </materialDesign:DrawerHost.LeftDrawerContent>

    <!-- 上メニューとコンテンツ -->
    <DockPanel>
        <materialDesign:ColorZone
            Padding="16"
            DockPanel.Dock="Top"
            Mode="PrimaryMid">
            <DockPanel HorizontalAlignment="Stretch">
                <StackPanel Orientation="Horizontal">
                    <!-- ハンバーガー本体 -->
                    <ToggleButton x:Name="toggleButtonMenu" Style="{StaticResource MaterialDesignHamburgerToggleButton}" />

                    <!-- 好きな上メニュー項目を配置する -->
                </StackPanel>
            </DockPanel>
        </materialDesign:ColorZone>

        <!-- DataGrid などメインコンテンツを配置する -->
    </DockPanel>
</materialDesign:DrawerHost>
</mah:MetroWindow>

理解してしまえば「なんだ、そういうことか」というレベルなんですけど、 この考え方をうまく説明しているサイトが中々なくて、苦労しました。

まとめ

マテリアルデザインで作ると見た目はいいのですが、実装が大変だと理解できました。 これに、UserControl と DialogHost を組み合わせてみたり、 UserControl でメイン画面のコンテンツを切り替えたりと、 次から次へと高難度の連続技が続くのですが、この辺りになると MVVMフレームワークを導入することになりそうです。

流石に、MVVM入れてガチで作ると、お手軽アプリが未完成になりそうなので、 一旦、現状までの知識で進めて行こうと思います。

MaterialDesign Xaml Toolkit のソースを見てみましたが、 UserControl を使った実装は理解できませんでした。 この辺りは、今後の課題にしておきましょう。

最後に参考サイトを掲載しておきます。 では、皆さん、よい旅を。

次回以降のリンクはこちら。

sabakunotabito.hatenablog.com

sabakunotabito.hatenablog.com

sabakunotabito.hatenablog.com

参考サイト