WPF多语言GUI即时切换

时间:2021-05-04 04:06:55

resource files are already created. swtich the language after a restart of the app works currently.

资源文件已经创建。当应用程序重新启动后,该语言开启。

is it possible to switch the language of the gui(Ribbon) on the fly ?

是否可以动态切换gui(Ribbon)的语言?

already tried: change cultureinfo and invoke initializecomponents doesn't work.

已经尝试过:更改cultureinfo并调用initializecomponents不起作用。

2 个解决方案

#1


I've bounced on this topic too a while ago. What i found was that it is possible, but it will take some effort. The only solution i recall is that you quit your application. At that moment a batch starts which will relaunch your application so the user won't freak out when the app suddenly quits and disappears. When your app has relaunched, it will reload all ui elements with the appropriate culture.

我刚才就这个话题反复说过。我发现它是可能的,但它需要一些努力。我记得唯一的解决方案就是退出你的申请。此时批量启动将重新启动您的应用程序,以便用户在应用程序突然退出并消失时不会惊慌失措。当您的应用重新启动时,它将重新加载具有适当文化的所有ui元素。

I haven't used this method because i don't like having to quit my app in order to make changes. But it is possible.

我没有使用这种方法,因为我不想退出我的应用程序以进行更改。但这是可能的。

What you are experiencing is that the culture does change in your app, but your controls aren't updated accordingly. A restart "fixes" this.

您所遇到的是文化确实在您的应用中发生了变化,但您的控件未相应更新。重启“修复”了这个。

Hope this helped a bit.

希望这有点帮助。

#2


I have encountered with the same problem and found a solution that works for me. It does not require converters, but a piece of code is still necessary. The .Net 4.5 framework is used.

我遇到了同样的问题,并找到了适合我的解决方案。它不需要转换器,但仍需要一段代码。使用.Net 4.5框架。

Two unobvious things are needed in order to switch languages on-the-fly:

为了即时切换语言,需要两个不明显的事情:

  1. Use another flavour of binding to static properties, replace <TextBlock Text="{Binding Source={x:Static p:Resources.LocalizedString}}"/> with <TextBlock Text="{Binding Path=(p:Resources.LocalizedString)}"/>. (The binding syntax with parentheses is used for attached properties and static properties. As a side effect, the XAML designer will show empty strings for these properties.)

    使用另一种绑定到静态属性的方法,将 替换为 。 (带括号的绑定语法用于附加属性和静态属性。作为副作用,XAML设计器将为这些属性显示空字符串。)

  2. Change notifications do not work with resources. To workaround that, static bindings are manually refreshed by the following code:

    更改通知不适用于资源。要解决此问题,请通过以下代码手动刷新静态绑定:

    // ... after the current culture has changed
    UpdateStaticBindings(Application.Current.MainWindow, typeof(Properties.Resources), true);
    
    /// <summary>
    /// Update all properties bound to properties of the given static class.
    /// Only update bindings like "{Binding Path=(namespace:staticClass.property)}".
    /// Bindings like "{Binding Source={x:Static namespace:staticClass.property}}" cannot be updated.
    /// </summary>
    /// <param name="obj">Object that must be updated, normally the main window</param>
    /// <param name="staticClass">The static class that is used as the binding source, normally Properties.Resources</param>
    /// <param name="recursive">true: update all child objects too</param>
    static void UpdateStaticBindings(DependencyObject obj, Type staticClass, bool recursive)
    {
        // Update bindings for all properties that are statically bound to
        // static properties of the given static class
        if (obj != null)
        {
            MarkupObject markupObject = MarkupWriter.GetMarkupObjectFor(obj);
    
            if (markupObject != null)
            {
                foreach (MarkupProperty mp in markupObject.Properties)
                {
                    if (mp.DependencyProperty != null)
                    {
                        BindingExpression be = BindingOperations.GetBindingExpression(obj, mp.DependencyProperty) as BindingExpression;
    
                        if (be != null)
                        {
                            // Only update bindings like "{Binding Path=(namespace:staticClass.property)}"
                            if (be.ParentBinding.Path.PathParameters.Count == 1)
                            {
                                MemberInfo mi = be.ParentBinding.Path.PathParameters[0] as MemberInfo;
                                if (mi != null && mi.DeclaringType.Equals(staticClass))
                                {
                                    be.UpdateTarget();
                                }
                            }
                        }
                    }
                }
            }
    
            // Iterate children, if requested
            if (recursive)
            {
                foreach(object child in LogicalTreeHelper.GetChildren(obj))
                {
                    UpdateStaticBindings(child as DependencyObject, staticClass, true);
                }
            }
        }
    }
    

#1


I've bounced on this topic too a while ago. What i found was that it is possible, but it will take some effort. The only solution i recall is that you quit your application. At that moment a batch starts which will relaunch your application so the user won't freak out when the app suddenly quits and disappears. When your app has relaunched, it will reload all ui elements with the appropriate culture.

我刚才就这个话题反复说过。我发现它是可能的,但它需要一些努力。我记得唯一的解决方案就是退出你的申请。此时批量启动将重新启动您的应用程序,以便用户在应用程序突然退出并消失时不会惊慌失措。当您的应用重新启动时,它将重新加载具有适当文化的所有ui元素。

I haven't used this method because i don't like having to quit my app in order to make changes. But it is possible.

我没有使用这种方法,因为我不想退出我的应用程序以进行更改。但这是可能的。

What you are experiencing is that the culture does change in your app, but your controls aren't updated accordingly. A restart "fixes" this.

您所遇到的是文化确实在您的应用中发生了变化,但您的控件未相应更新。重启“修复”了这个。

Hope this helped a bit.

希望这有点帮助。

#2


I have encountered with the same problem and found a solution that works for me. It does not require converters, but a piece of code is still necessary. The .Net 4.5 framework is used.

我遇到了同样的问题,并找到了适合我的解决方案。它不需要转换器,但仍需要一段代码。使用.Net 4.5框架。

Two unobvious things are needed in order to switch languages on-the-fly:

为了即时切换语言,需要两个不明显的事情:

  1. Use another flavour of binding to static properties, replace <TextBlock Text="{Binding Source={x:Static p:Resources.LocalizedString}}"/> with <TextBlock Text="{Binding Path=(p:Resources.LocalizedString)}"/>. (The binding syntax with parentheses is used for attached properties and static properties. As a side effect, the XAML designer will show empty strings for these properties.)

    使用另一种绑定到静态属性的方法,将 替换为 。 (带括号的绑定语法用于附加属性和静态属性。作为副作用,XAML设计器将为这些属性显示空字符串。)

  2. Change notifications do not work with resources. To workaround that, static bindings are manually refreshed by the following code:

    更改通知不适用于资源。要解决此问题,请通过以下代码手动刷新静态绑定:

    // ... after the current culture has changed
    UpdateStaticBindings(Application.Current.MainWindow, typeof(Properties.Resources), true);
    
    /// <summary>
    /// Update all properties bound to properties of the given static class.
    /// Only update bindings like "{Binding Path=(namespace:staticClass.property)}".
    /// Bindings like "{Binding Source={x:Static namespace:staticClass.property}}" cannot be updated.
    /// </summary>
    /// <param name="obj">Object that must be updated, normally the main window</param>
    /// <param name="staticClass">The static class that is used as the binding source, normally Properties.Resources</param>
    /// <param name="recursive">true: update all child objects too</param>
    static void UpdateStaticBindings(DependencyObject obj, Type staticClass, bool recursive)
    {
        // Update bindings for all properties that are statically bound to
        // static properties of the given static class
        if (obj != null)
        {
            MarkupObject markupObject = MarkupWriter.GetMarkupObjectFor(obj);
    
            if (markupObject != null)
            {
                foreach (MarkupProperty mp in markupObject.Properties)
                {
                    if (mp.DependencyProperty != null)
                    {
                        BindingExpression be = BindingOperations.GetBindingExpression(obj, mp.DependencyProperty) as BindingExpression;
    
                        if (be != null)
                        {
                            // Only update bindings like "{Binding Path=(namespace:staticClass.property)}"
                            if (be.ParentBinding.Path.PathParameters.Count == 1)
                            {
                                MemberInfo mi = be.ParentBinding.Path.PathParameters[0] as MemberInfo;
                                if (mi != null && mi.DeclaringType.Equals(staticClass))
                                {
                                    be.UpdateTarget();
                                }
                            }
                        }
                    }
                }
            }
    
            // Iterate children, if requested
            if (recursive)
            {
                foreach(object child in LogicalTreeHelper.GetChildren(obj))
                {
                    UpdateStaticBindings(child as DependencyObject, staticClass, true);
                }
            }
        }
    }