0

I have this piece of code which works:

'Calls after changing Thread.CurrentThread.CurrentUICulture
'and Threading.Thread.CurrentThread.CurrentCulture

'MainPagesBaseForm.vb
Imports System.ComponentModel

Protected Overridable Sub ChangeUILang()
    Dim t As Type = Me.GetType
    Dim resMgr As ComponentResourceManager
    While (Not t.Equals(GetType(Form)))
        resMgr = New ComponentResourceManager(t)
        Try
            ChangeUILangWork(Me, resMgr)
        Catch ex As Resources.MissingManifestResourceException
            'resource file doesn't exist, skip
        End Try
        t = t.BaseType
    End While
End Sub

Private Sub ChangeUILangWork(ctr As Control, resMgr As ComponentResourceManager)
    For Each ctrUnit As Control In ctr.Controls
        If ctrUnit.Visible Then
            'Change Lang for the control
            resMgr.ApplyResources(ctrUnit, ctrUnit.Name, _ 
            Thread.CurrentThread.CurrentUICulture)
            'override visiblity in designer. Already checked to be visible
            ctrUnit.Visible = True
            'For image based controls
            If (TypeOf ctrUnit Is ImageBaseControlI) Then
                DirectCast(ctrUnit, ImageBaseControlI).ChangeLang()
            End If
            'Recursion
            If ctrUnit.HasChildren Then
                If TypeOf ctrUnit Is UserControl Then
                    'Look into its own .resx for user controls
                    Dim resMgr2 As New ComponentResourceManager(ctrUnit.GetType)
                    ChangeUILangWork(ctrUnit, resMgr2)
                Else
                    ChangeUILangWork(ctrUnit, resMgr)
                End If
                'For panels with custom paint 
                ctrUnit.Invalidate()
            End If
        End If
    Next ctrUnit
End Sub
  1. Is there any proper way to change the UI language at run-time, including user controls and inhered controls, instead of applying all resource files to all elements like this? Shouldn't the controls know where their localization data is?

  2. Is there anyway to check whether a resource file exist? I would like to avoid empty try catch if possible.


Background:

Hi, I have a WinForm application that needs to change its UI Language at run-time. Structure of the forms are as following:

'This defines the layout of the main pages
Public Class MainPageBaseForm    
    Inherits Form
    Protected LblHeader As Label 'Added and localized from designer       
    '...
End Class

'This defines common event handlers for pages related to books
'No localization file for this class
Public Class BooksBaseForm
    Inherits MainPageBaseForm
    Event BookStatusChanged(sender As Object, e As BookStatusEventArgs)
    '...
End Class   

'Individual pages / forms
Public Class FrmBooks001
    Inherits BooksBaseForm
    Protected LblDesc As Label 'Localized Label added from designer
    Protected SearchKeysInputFields As BooksEnqInForm 'Localized user control
    Protected BntChLang As Button 'Button to switch UI culture
    'Other controls like textboxes & buttons for this page
    '...
End Class

When the switch culture button clicked, the Form's Controls should be refreshed. I have found the way that works for simple forms(How do I change the culture of a WinForms application at runtime):

Private Sub ChangeUILang(parentCtr As Control)
    Dim resMgr As New System.ComponentModel.ComponentResourceManager(GetType(FrmBooks001))
    For Each ctr As Control In parentCtr.Controls
        resources.ApplyResources(ctr, ctr.Name, New CultureInfo("zh"))
        if ctr.HasChildren then
            ChangeUILang(ctr)
        end if
    Next
End Sub

However this only works on controls directly defined in FrmBooks001, and only vanilla controls (not UserControl). I figured the reason from this post: Switching language (cultureinfo/globalization) does not affect ToolStripMenuItems

you are looking for the localization information in System.Windows.Forms.ToolStripMenuItem.resx file, but you want to look in your Forms resources file.

(The situation here is the opposite which the UserControls has their own .resx files)

So the only solution (I can thought of) is to loop through all resource file of the classes in inheritance tree and the UserControls (and apply all redundantly!). Sorry for the long post, please see the top for what I currently use and the questions. Thanks in advance.

Community
  • 1
  • 1
jack3694078
  • 993
  • 1
  • 9
  • 20
  • Why don't you close the form and open it with new culture? – Reza Aghaei Nov 30 '15 at 09:01
  • @Reza Aghaei Because it is the main form of the application – jack3694078 Nov 30 '15 at 09:08
  • In such case If I used localization infrastructure of windows forms designer, I prefer to store the selected culture in a setting, then if the user confirms, I restart the application using `Application.Restart()` and apply the new culture at startup. – Reza Aghaei Nov 30 '15 at 09:14
  • @Reza Aghaei It is for public workstations(sort of) so restarting it on User input is not really an option. But it may actually worth the rework to make another hidden main form if it's all that simple now that I think about it... – jack3694078 Nov 30 '15 at 09:19
  • Also you may find [this answer](http://stackoverflow.com/a/33948879/3110834) useful as an idea. It's totally different approach that makes it easy to apply culture changes but it may need some improvements to fit your requirements. Let me know if you find that answer helpful :) – Reza Aghaei Nov 30 '15 at 09:21
  • VB.NET makes it particularly easy to re-create the main form without that terminating your app. Project > Properties > Application tab > Shutdown mode = "When last form closes". – Hans Passant Nov 30 '15 at 09:59

0 Answers0