WPF DLL化したユーザーコントロール画面多言語対応

# やりたいこと
プロジェクト`LanguageSwitchSample`はあるユーザーコントロールライブラリ`WpfControlLibrary1`の`DLL`を参照して、参照されたユーザーコントロール画面の多言語対応を実現したい。

サンプルコード[ダウンロード](https://github.com/Minoa0313/Sample.git)
パス：`Sample/LanguageSwitchSample_DLL/`

# 流れ
以下のファイルを作成する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2074893/0a71611d-9dba-0a04-cb49-7271117b040e.png)

## LanguageSwitchSample の作成
[WPFプログラムの多言語対応](https://qiita.com/aonim/items/36d3894c5fe721d9ab49)を参照して作成する。
又は[ここ](https://github.com/Minoa0313/Sample.git)からダウンロードする。パス：`Sample/LanguageSwitchSample/`

## WpfControlLibrary1 の作成
1. ソリューションにWPFユーザーコントロールライブラリを追加する
1. `lang`フォルダを作成し、言語ファイル`en.xaml`と`jp.xaml`をしたに置く。（LanguageSwitchSample と区別するため、名前が違う）
    ```en.xaml
    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
                        xmlns:sys="clr-namespace:System;assembly=mscorlib">
        <!--新規追加-->
    
        <sys:String x:Key="text1">Text1</sys:String>
        <sys:String x:Key="text2">Text2</sys:String>
    
    </ResourceDictionary>
    ```

    ```jp.xaml
    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
                        xmlns:sys="clr-namespace:System;assembly=mscorlib">
        <!--新規追加-->
    
        <sys:String x:Key="text1">テキスト1</sys:String>
        <sys:String x:Key="text2">テキスト2</sys:String>
    
    </ResourceDictionary>
    
    ```

3. UserControlの画面は簡単で、二つの`TextBlock`だけがある

    ```UserControl1.xaml
    <UserControl x:Class="WpfControlLibrary1.UserControl1"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 xmlns:local="clr-namespace:WpfControlLibrary1"
                 mc:Ignorable="d" 
                 d:DesignHeight="300" d:DesignWidth="300">
        <UserControl.Resources>
            <ResourceDictionary>
                <ResourceDictionary.MergedDictionaries>
                    <ResourceDictionary Source="lang/en.xaml"/>
                </ResourceDictionary.MergedDictionaries>
            </ResourceDictionary>
        </UserControl.Resources>
        
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>
    
            <TextBlock Text="{DynamicResource text1}" FontSize="40" VerticalAlignment="Center"/>
            <TextBlock Text="{DynamicResource text2}" FontSize="40" Grid.Row="1" VerticalAlignment="Center"/>
    
        </Grid>
    </UserControl>
    
    ```
4. Class1 の作成
   今二つの言語しか使わないので、関数`LanguageSwitch`の引数を`bool`にした。
実際使うとき、引数を`Enum`型にして、複数言語の切替が実現できる。
    ```Class1.cs
    using System;
    using System.Windows;
    
    namespace WpfControlLibrary1
    {
        public interface IWindowInfo
        {
            public bool LanguageSwitch(bool isEnglish);
        }
    
        public class Class1:IWindowInfo
        {
            private UserControl1 control;
    
            public Class1(UserControl1 obj)
            {
                control = obj;
            }
    
            public bool LanguageSwitch(bool isEnglish)
            {
                ResourceDictionary? langRd = null;
                string langFile = "";
    
                if (isEnglish)
                {
                    langFile = "lang/en.xaml";
                }
                else
                {
                    langFile = "lang/jp.xaml";
                }
    
                try
                {
                    // ここは大事！
                    // DLL から リソースディレクトリを使うとき、
                    // Uri の書き方 new Uri("/現在のプロジェクト名;component/相対パス",UriKind.Relative)
                    langRd = Application.LoadComponent(new Uri("/WpfControlLibrary1;component/" + langFile, UriKind.Relative)) as ResourceDictionary;
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                    return false;
                }
    
                if (langRd != null)
                {
                    if (control.Resources.MergedDictionaries.Count > 0)
                    {
                        // 設計画面で言語リソースディレクトリを0番に固定で設定したので
                        control.Resources.MergedDictionaries[0] = langRd;
                    }
                    else
                    {
                        control.Resources.MergedDictionaries.Add(langRd);
                    }
                }
    
                return true;
            }
        }
    }
    
    ```

以上で、クラスライブラリを完成した、次から、`LanguageSwitchSample`から`WpfControlLibrary1`を呼び出す。

## DLLを呼び出す
1. `DLL`を参照する
1. 画面を修正する
   下のコードをネームスペースに追加する
   `xmlns:UserControl="clr-namespace:WpfControlLibrary1;assembly=WpfControlLibrary1"`
   画面のサイズは`300*300` から `300*600`に変更する。
   そして`RowDefinition`一行を追加して、呼び出されたユーザーコントロールをここに置く。
   一番下で`UserControl1`を呼び出す
    ```MainWindow.xaml
    <Window x:Class="LanguageSwitchSample.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:UserControl="clr-namespace:WpfControlLibrary1;assembly=WpfControlLibrary1"
            xmlns:local="clr-namespace:LanguageSwitchSample"
            mc:Ignorable="d"
            Title="MainWindow" Height="600" Width="300">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition Height="2*"/>
            </Grid.RowDefinitions>
    
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
    
            <Button Grid.Row="0" Margin="10" FontSize="60" Content="en" Click="Button_en_Click"/>
            <Button Grid.Row="1" Margin="10" FontSize="60" Content="ja" Click="Button_ja_Click"/>
    
    
            <!--DynamicResource Start ここでkeyの値を読み込む-->
            <TextBlock Grid.Row="0" Grid.Column="1" FontSize="60" VerticalAlignment="Center" Text="{DynamicResource Start}"/>
            <TextBlock Grid.Row="1" Grid.Column="1" FontSize="60" VerticalAlignment="Center" Text="{DynamicResource Stop}"/>
    
            <UserControl:UserControl1 x:Name="uc1" Grid.Row="2" Grid.ColumnSpan="2"/>
        </Grid>
    </Window>
    
    ```

## Main画面のクリックイベントを編集する
```MainWindow.xaml.cs
using System;
using System.Windows;
using WpfControlLibrary1;

namespace LanguageSwitchSample
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        Class1 class1;

        public MainWindow()
        {
            InitializeComponent();

            class1 = new Class1(uc1);
        }

        private void Button_en_Click(object sender, RoutedEventArgs e)
        {
            ChangeLang(@"lang/english.xaml");
            class1.LanguageSwitch(true);
        }

        private void ChangeLang(string path)
        {
            ResourceDictionary langRd = null;
            string langFile = path;

            try
            {
                langRd = Application.LoadComponent(new Uri(langFile, UriKind.Relative)) as ResourceDictionary;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

            if (langRd != null)
            {
                if (this.Resources.MergedDictionaries.Count > 0)
                {
                    this.Resources.MergedDictionaries[0] = langRd;
                }
                else
                {
                    this.Resources.MergedDictionaries.Add(langRd);
                }
            }
        }

        private void Button_ja_Click(object sender, RoutedEventArgs e)
        {
            ChangeLang(@"lang/japanses.xaml");
            class1.LanguageSwitch(false);
        }
    }
}

```

# 実行結果
`en`ボタンを押すと、ユーザーコントロールの文字が英語になる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2074893/2df784a0-3819-91cf-14c8-3a1e04c6ca84.png)
`ja`ボタンを押すと、ユーザーコントロールの文字が日本語になる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2074893/155bc659-e386-6e4e-40a9-f3bfe11f0b7a.png)