

WPF多言語で調べた場合、動的切替のサンプルはいくつかありますが、XAMLへの記述が肥大化しそうだったため、添付プロパティで多言語化しているのですが、画面上のボタンからカルチャを変更しても、画面上のテキストが変化しません。

多言語処理は添付プロパティのOnTextChangedの部分で行っているため、OnTextChangedイベントが動かない限り、言語が切り替わらない事までは分かっているのですが、解決策が思いつきませんでした。  
カルチャ変更時に、OnTextChangedイベントを発生もしくはそれ以外の方法で切り替える方法があればご教授ください。

※MVVMライブラリとしてCaliburn.Microを使用しています

添付プロパティ

[code]

    public class MultilingualText
    {
        public static DependencyProperty MultilingualTextProperty
            = DependencyProperty.RegisterAttached("Text",
                typeof(string),
                typeof(MultilingualText),
                new FrameworkPropertyMetadata("", new PropertyChangedCallback(OnTextChanged)));
    
        public static void SetText(DependencyObject obj, string value)
            => obj.SetValue(MultilingualTextProperty, value);
    
        public static string GetText(DependencyObject obj)
            => (string)obj.GetValue(MultilingualTextProperty);
    
        private static void OnTextChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            if (obj is TextBlock textblock)
            {
                // Resourcesから現在のカルチャに紐づく文字列を取得
                textblock.Text = Properties.Resources.ResourceManager.GetString(e.NewValue.ToString(), CultureService.Current.GetCurrentCulture());
            }
        }
    }
    
[/code]

Calutureクラス

[code]

    class CultureService : PropertyChangedBase
    {
        public static CultureService Current { get; } = new CultureService();
        /// <summary>
        /// 多言語化されたリソースを取得
        /// </summary>
        private CultureInfo _Resources;
        public CultureInfo Resources
        {
            get { return _Resources; }
            set { this.SetProperty(ref _Resources, value); }
        }
    
        /// <summary>
        /// カルチャを変更
        /// </summary>
        public void ChangeCulture(string name)
        {
            Resources = CultureInfo.GetCultureInfo(name);
        }
    
        /// <summary>
        /// カルチャを取得
        /// </summary>
        public CultureInfo GetCurrentCulture()
        {
            return Resources;
        }
    }
    
[/code]

XAML

[code]

    <Grid>
        <TextBlock local:MultilingualText.Text="HelloWorld"/>
    </Grid>
    
[/code]

ボタンイベント

[code]

    private void Button1_Click(object sender, RoutedEventArgs e)
    {
        CultureService.Current.ChangeCulture("ja-JP");
    }
    private void Button2_Click(object sender, RoutedEventArgs e)
    {
        CultureService.Current.ChangeCulture("en-US");
    }
    
[/code]


CC BY-SA 4.0
2020-07-06T07:03:02.857
68333
2020-07-09T13:20:33.793
2020-07-06T07:26:09.013
3060
39523
question
wpf xaml
WPF 添付プロパティで動的に多言語化したい


MultilingualText.OnTextChanged() で CultureService.Current の PropertyChanged
イベント監視を登録することで実現してみました。  
メモリリークを避けるため、弱いイベントパターンを使用しています。

[code]

        public class MultilingualText
        {
            private static readonly DependencyProperty WeakEventListenerProperty
                 = DependencyProperty.RegisterAttached("WeakEventListener",
                     typeof(IWeakEventListener),
                     typeof(MultilingualText),
                     new PropertyMetadata(null));
    
            private static void SetWeakEventListener(DependencyObject obj, IWeakEventListener value)
                => obj.SetValue(WeakEventListenerProperty, value);
    
            private static IWeakEventListener GetWeakEventListener(DependencyObject obj)
                => (IWeakEventListener)obj.GetValue(WeakEventListenerProperty);
    
    
            public static DependencyProperty MultilingualTextProperty
                = DependencyProperty.RegisterAttached("Text",
                    typeof(string),
                    typeof(MultilingualText),
                    new FrameworkPropertyMetadata("", new PropertyChangedCallback(OnTextChanged)));
    
            public static void SetText(DependencyObject obj, string value)
                => obj.SetValue(MultilingualTextProperty, value);
    
            public static string GetText(DependencyObject obj)
                => (string)obj.GetValue(MultilingualTextProperty);
    
            private static void OnTextChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
            {
                InitializeEventListner(obj);
                UpdateText(obj);
            }
    
    
            private static void UpdateText(DependencyObject obj)
            {
                if (obj is TextBlock textblock)
                {
                    // Resourcesから現在のカルチャに紐づく文字列を取得
                    textblock.Text = Properties.Resources.ResourceManager.GetString(GetText(obj), CultureService.Current.GetCurrentCulture());
                }
            }
    
            private static void InitializeEventListner(DependencyObject obj)
            {
                if (GetWeakEventListener(obj) != null) return;
    
                var propertyChangedListener = new PropertyChangedWeakEventListener(obj, RaisePropertyChanged);
                PropertyChangedEventManager.AddListener(CultureService.Current, propertyChangedListener, nameof(CultureService.Resources));
                SetWeakEventListener(obj, propertyChangedListener);
            }
    
            private static void RaisePropertyChanged(DependencyObject obj, string propertyName)
            {
                UpdateText(obj);
            }
    
    
            class PropertyChangedWeakEventListener : IWeakEventListener
            {
                private DependencyObject _obj;
                private Action<DependencyObject, string> _raisePropertyChangedAction;
    
                public PropertyChangedWeakEventListener(DependencyObject obj, Action<DependencyObject, string> raisePropertyChangedAction)
                {
                    _obj = obj;
                    _raisePropertyChangedAction = raisePropertyChangedAction;
                }
    
                public bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
                {
                    if (typeof(PropertyChangedEventManager) != managerType)
                    {
                        return false;
                    }
    
                    if (e is PropertyChangedEventArgs evt)
                    {
                        _raisePropertyChangedAction(_obj, evt.PropertyName);
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
            }
    
        }
    
[/code]


CC BY-SA 4.0
2020-07-09T09:06:35.753
68435
2020-07-09T13:20:33.793
2020-07-09T13:20:33.793
14817
14817
68333
answer