开发者

Multiple usercontrols with different data injected showing same data

Working on a page where I create new instances of a usercontrol I wrote, based on data. I pass in filtered data to the user control using constructor injection. However, when the user controls render, only the last set of data injected in is rendered for all user controls. It appears I'm referencing the same instance rather than creating a new, independent one. Ideas?

 protected void Page_Init(object sender, EventArgs e)
        {
            var data = <my data comes from here>;
            var yearsInData = data.OrderByDescending(x=>x.Year).Select(x => x.Year).Distinct();

            foreach(var year in yearsInData)
            {
                var employers = data.OrderBy(x=>x.EmployerName).Where(x => x.Year == year).Select(x => x.EmployerName).Distinct();
                foreach (var employer in employers)
                {
                    var eob = data.Where(x => x.Year == year).Where(x => x.EmployerName == employer);
                    if (eob.Count() > 0)
                    {
                        var ctl = LoadControl(@"~\Shared\Controls\AnnualEOBControl.ascx", eob);
                        pnlMain.Controls.Add(ctl);
                    }
                }
            }
        }

Here is the LoadControl method:

private UserControl LoadControl(string userControlPath, params object[] constructorParameters)
        {
            var constParamTypes = new List<Type>();
            foreach (var constParam in constructorParameters)
            {
                constParamTypes.Add(constParam.GetType());
            }

            var ctl = Page.LoadControl(userControlPath) as UserControl;

            // Find the relevant constructor
            if (ctl != null)
            {
                var constructor = ctl.GetType().BaseType.GetConstructor(constParamTypes.ToArray开发者_运维问答());

                // And then call the relevant constructor
                if (constructor == null)
                {
                    throw new MemberAccessException("The requested constructor was not found on : " + ctl.GetType().BaseType);
                }
                constructor.Invoke(ctl, constructorParameters);
            }

            // Finally return the fully initialized UC
            return ctl;
        } 


It smells like a closure issue. My hunch is eob is merely being reassigned a value during each iteration as opposed to recreated. Since your controls all reference eob as opposed to the data returned by eob, they would all use the same value when it's time to render.

What does your LoadControl overload look like? I read through the article you referenced, but I'd like to see what you did, specifically. I wonder if simply reassigning values from eob to a variable declared inside your LoadControl method would get you over the hump. Force the controls to use a variable from a tighter scope so they can't physically see each other's arguments.

Edit: Found an SO reference on the topic: What are 'closures' in .NET?

Give this a whirl:

private UserControl LoadControl(string userControlPath, params object[] constructorParameters)
    {
        var constParamTypes = new List<Type>();
        foreach (var constParam in constructorParameters)
        {
            constParamTypes.Add(constParam.GetType());
        }

        var ctl = Page.LoadControl(userControlPath) as UserControl;

        // Find the relevant constructor
        if (ctl != null)
        {
            var constructor = ctl.GetType().BaseType.GetConstructor(constParamTypes.ToArray());

            // And then call the relevant constructor
            if (constructor == null)
            {
                throw new MemberAccessException("The requested constructor was not found on : " + ctl.GetType().BaseType);
            }

            // constructor.Invoke(ctl, constructorParameters);
            object[] cp = constructorParameters;
            constructor.Invoke(ctl, cp);
        }

        // Finally return the fully initialized UC
        return ctl;
    } 


If I had this issue and there was a base class I could instrument and a way to produce a trace of some kind without too much trouble, I'd

  • put a const instance member Guid and a DateTime, both initializes it in the constructor
  • put a few ms sleep between separate calls to the constructor so the timestamps

I'm just thinking that might give a hint as to what's going on and lead to the root of it.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜