XAMLMarkupExtensions/WPFLocalizeExtension

Switching .dlls freezes application for way too long.

skowront opened this issue · 6 comments

The idea is simple. Suppose there are multiple libraries, each provides it's own localization resources and it's own windows.
Therefore:

        xmlns:lexp="clr-namespace:WPFLocalizeExtension.Providers;assembly=WPFLocalizeextension" 
        lexp:ResxLocalizationProvider.DefaultAssembly="Project.Common.EntityFramework"
        lexp:ResxLocalizationProvider.DefaultDictionary="SR"

is pretty common in code (with defaultassembly and defaultdictionary adjussted to each library of course).
So far so good, library works perfectly fine.
However InitializeComponent() function (not directly) calls the GetResourceManager function from ResxLocalizationProvicerBase.cs which is totally fine untill

// if no one was found, exception
                if (resManager == null)
                    throw new ArgumentException(string.Format("No resource manager for dictionary '{0}' in assembly '{1}' found! ({1}.{0})", resourceDictionary, resourceAssembly));

                // Add the ResourceManager to the cachelist
                Add(resManKey, resManager);

                try
                {
                    // Look in all cultures and check available ressources.
                    foreach (var c in SearchCultures)
                    {
                        var rs = resManager.GetResourceSet(c, true, false);
                        if (rs != null)
                            AddCulture(c);
                    }
                }
                catch
                {
                    // ignored
                }

I am especially talking about this guy:

var rs = resManager.GetResourceSet(c, true, false); 

He blocks the whole application for many seconds just to scroll through all available cultures. The GetResourceSet method is way to slow to use it like this. This bad boy throws many
Exception thrown: 'System.IO.FileNotFoundException' in System.Private.CoreLib.dll and that is painfull for VisualStewdio
Usually no application provides all 768 cultures and oh boy, waiting for the application to throw all those exceptions is too long.

Personally, I could just make a join of SearchCultures and Directories in my assembly folder.

// Look in all cultures and check available ressources.
                    var assemblyDir = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
                    var directories = Directory.GetDirectories(assemblyDir);
                    var directoryNames = new List<string>();
                    foreach (var directory in directories)
                    {
                        directoryNames.Add(directory.Remove(0, Path.GetDirectoryName(directory).Length).Replace("\\",""));
                    }
                    var joined = new List<CultureInfo>();
                    foreach (var culture in SearchCultures)
                    {
                        if(directoryNames.Any(x=>x.ToLower()==culture.Name.ToLower()))
                        {
                            joined.Add(culture);
                        }
                    }
                    foreach (var c in joined)
                    {
                        var rs = resManager.GetResourceSet(c, true, false);
                        if (rs != null)
                            AddCulture(c);
                    }

The problem is only uncomfortable for a developper, without VisualStudio the problem is barely visible. I did not find any way to configure VisualStewdio to ignore those exceptions not only by not showing, but also by not handling them so the debugging session could speed up.

If my issue is redundant, please let me know, I'll remove it, but I did not find anywhere any usefull information about this lag, with proper analysis.

konne commented

@Karnah any idea, maybe to do it better if the extension running inside of VS?

Hello! Sorry for really long answer.
@skowront, this problem appears when you Debug your application? Did you try to specify SearchCultures yourself? If it works, I think this is the best solution.

As for me resManager.GetResourceSet has really complicated logic and I affraid problems because of it. I think your solution (with some changes, because you shouldn't use Assembly.GetExecutingAssembly() and handle if resources located at subdirectory) will work at 99.9% of cases, but I'm not sure if it's worth it.
Also I didn't have this problem working in VS. Probably it's because I have settings Just My Code.

Yes, only while VS is attached to the process. When I run the application without VS there is no issue, and everything works seamlessly.

I would try to specify SearchCultures myself, yet i'm not aware how exactly (unless you just mean to hardcode it somewhere :D ).

Oops, yes, I offered to hardcode it. Sample:

(LocalizeDictionary.Instance.DefaultProvider as ResxLocalizationProvider).SearchCultures =
new List<System.Globalization.CultureInfo>()
{
System.Globalization.CultureInfo.GetCultureInfo("de-de"),
System.Globalization.CultureInfo.GetCultureInfo("en"),
System.Globalization.CultureInfo.GetCultureInfo("he"),
System.Globalization.CultureInfo.GetCultureInfo("ar"),
};

But probably it's better to use ResxLocalizationProvider.Instance.SearchCultures directly and do it at App.xam.cs

Also it's the official solution of this problem like described here #262
@skowront, could you say if it for any reason doesn't suit you?

Had I see this solutions earlier I wouldn't have opened this issue. However I'd say it does not seem a clean solution in terms of maintaining the code, but also totally valid.