Click here to Skip to main content
15,880,608 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more: , +
Ok, this may be a long question, but here it is:

First, why I can't use built in localization:
The built-in localization only works if #1, the control properties have the "Localizable" attribute applied to them, and #2 only if they are top level properties. Since I need to be able to localize nested properties on items that don't have the Localizable attribute applied, I have to roll my own.

So, all the forms in this project derive from a single base form, which has the following two functions on it:

C#
private void ResetResources()
{
    for (int i = 0; i < Controls.Count; i++)
    {
        Control c = Controls[i];
        ApplyResource(ref c, "Screens." + this.Name);
    }

    Invalidate(true);
}

private void ApplyResource(ref Control c, string baseName)
{
    ResourceService.ApplyResource(ref c, baseName + "." + c.Name);

    if (c.HasChildren)
    {
        for (int i = 0; i < c.Controls.Count; i++)
        {
            Control sc = c.Controls[i];
            ApplyResource(ref sc, baseName + "." + c.Name);
        }
    }
}


ResetResources is called when the culture is changed. I have a single static resource "service" that the form uses by calling this function:

C#
internal static void ApplyResource(ref Control c, string fullControlName)
{
    string resourceName = fullControlName + ".Text";
    string value = c.Text;

    try
    {
        ResourceSet rSet = _resourceManager.GetResourceSet(_currentCulture, true, true);

        Dictionary<string, string> resources = GetResourcesFor(rSet, fullControlName);

        foreach (KeyValuePair<string, string> kvp in resources)
            SetProperty(ref c, kvp.Key, kvp.Value);
    }
    catch { }

    if (!string.IsNullOrEmpty(value))
        c.Text = value;
}


Most of it is pretty basic, it uses a ResourceManager and ResourceSet to get the appropriate resources. The GetResourcesFor (which I won't post the code for since its irrelevant) just gets all the resources beginning with the control name, and that works great.

The problem comes in when I set the properties through reflection. Since I don't know what the property name is (its in the resource file), I use the SetProperty and GetSubObject function, which is:

C#
private static void SetProperty(ref Control c, string property, object value)
{
    string[] propPath = null;

    if (property.Contains('.'))
        propPath = new string[] { property };
    else
        propPath = property.Split('.');

    object currentObject = c;
    object parentObject = c;
    PropertyInfo pInfo = null;

    for (int i = 0; i < propPath.Length; i++)
    {
        parentObject = currentObject;
        currentObject = GetSubObject(currentObject, propPath[i], out pInfo);

        if (currentObject == null)
            return;
    }

    if (pInfo != null)
    {
        if (c.InvokeRequired)
            c.Invoke((MethodInvoker)delegate { pInfo.SetValue(parentObject, value, null); });
        else
        {
            pInfo.SetValue(parentObject, value, null);
            c.Invalidate(true);
        }
    }
}

private static object GetSubObject(object obj, string propName, out PropertyInfo pInfo)
{
    //Figure out if it's an index property...
    bool isIndex = false;
    int index = 0;
    pInfo = null;
    string pName = propName;

    if (propName.Contains('['))
    {
        isIndex = true;
        string idxStr = propName.Substring(propName.IndexOf('[') + 1);
        idxStr = idxStr.TrimEnd(']');

        if (!int.TryParse(idxStr, out index))
            return null;

        pName = propName.Substring(0, propName.IndexOf('['));
    }

    pInfo = obj.GetType().GetProperty(pName);

    if (pInfo == null)
        return null;

    if (!isIndex)
        return pInfo.GetValue(obj, null);
    else
    {
        IList objList = pInfo.GetValue(obj, null) as IList;

        if (objList == null)
            return null;

        return objList[index];
    }
}


The GetSubObject and everything works, and if I debug and set a breakpoint just after the pInfo.SetValue, the property is set correctly, but when the stack unwinds back to the form, the property is never updated! This doesn't seem to be a drawing problem, I'm really at a loss as I'm setting the property values in other places in the same fashion and for some reason this isn't working!

My idea is that because I'm indexing through the Controls collection that for some reason it isn't saving my changes (hence all the pointless "ref" in the function prototypes). I just don't know what the fix is. This is supposed to be dynamic, so I can't hard-code all the control names nor the properties, its just supposed to "work".

Any help would be great.
Posted

1 solution

Ok... I found it...

The problem was this line:

C#
internal static void ApplyResource(ref Control c, string fullControlName)
        {
            string resourceName = fullControlName + ".Text";
            string value = c.Text;
 
            try
            {
                ResourceSet rSet = _resourceManager.GetResourceSet(_currentCulture, true, true);
 
                Dictionary<string,> resources = GetResourcesFor(rSet, fullControlName);
 
                foreach (KeyValuePair<string,> kvp in resources)
                    SetProperty(ref c, kvp.Key, kvp.Value);
            }
            catch { }
            
            //THE PROBLEM WAS THESE TWO LINES
            if (!string.IsNullOrEmpty(value))
                c.Text = value;
        }


Originally I wrote this to just set a .Text property and SetProperty was returning a string, I missed removing those two lines.

Thanks for looking anyway :)
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900