1

I have a usercontrol that I have designed which has a picturebox on it. I want the image for the picturebox to come from a separate dll in my project where I store my images. I can manually go into the Designer.cs and set this.pictureBox1.Image = global::(Name of my dll).Properties.Resources.imageName; which produces the effect I want. The difficulty is that whenever I do something that causes the Designer.cs to regenerate, Visual studio insists on going and getting that image and serializing it to the control's resx file, then it replaces the reference with this.pictureBox1.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox1.Image")));.

I have tried working with the DesignerSerializationVisibility and its three settings. All I seem to be able to do with that is prevent Visual Studio from including the Image property at all, which causes my control to malfunction at run time.

I've looked into designing a custom CodeDomSerializer but I've not had any success with that at this point.

Is there any way to just tell Visual Studio to leave that property as it is and don't change it?

Michael Jordan
  • 382
  • 2
  • 13
  • 1
    What happens if you leave the image blank in the designer, and set it in code in the UserControl's constructor after `InitializeComponent()` is called? – Matthew Watson May 23 '21 at 11:29
  • Hmm, well, I need the image to show in the designer - it's a picture of a page and we are laying other controls on top of it and use the image for positioning the controls at design time. – Michael Jordan May 23 '21 at 11:34
  • Create a control that inherits from PictureBox and set that derived control's Image property in its constructor. Replace the UC's PictureBox with this new control. – TnTinMn May 23 '21 at 19:45

2 Answers2

0

For those who have kindly taken the time to consider this item or who may visit this in the future, I have discovered the resolution. Someone prior to me had set this up, so I was unaware of what they had done.

So, the goal was to have a dll that contained images, and when/if those images changed, you could just swap out the dll and the various controls in the other projects would automatically pick up those changes at runtime by simply replacing that single dll.

The method requires setting up a project with nothing but the image resources. Then link (not copy) the resx file from that project to the other ones that are using it. Then, once you put the global:: references in the Designer.cs, they will stay in there unmolested by Visual Studio.

Michael Jordan
  • 382
  • 2
  • 13
0
[DesignerSerializer(typeof(CustomCodeDomSerializer), typeof(CodeDomSerializer))]
    public class BaseUserControl : UserControl
    {

    }

    public class CustomCodeDomSerializer : CodeDomSerializer
    {
        public override object Serialize(IDesignerSerializationManager manager, object value)
        {
            var baseClassSerializer = (CodeDomSerializer)manager.GetSerializer(typeof(BaseUserControl).BaseType, typeof(CodeDomSerializer));
            var codeObject = baseClassSerializer.Serialize(manager, value);

            if (codeObject is CodeStatementCollection collection)
            {
                for (var i = 0; i < collection.Count; i++)
                {
                    var st = collection[i] as CodeVariableDeclarationStatement;
                    if (st?.Type.BaseType == typeof(ComponentResourceManager).FullName)
                    {
                        var ctr = new CodeTypeReference(typeof(MyCustomComponentResourceManager));
                        st.Type = ctr;
                        st.InitExpression = new CodeObjectCreateExpression(ctr, new CodeTypeOfExpression(manager.GetName(value)));
                    }
                }
            }

            return codeObject;
        }

        /// <inheritdoc />
        public override object Deserialize(IDesignerSerializationManager manager, object codeObject)
        {
            CodeDomSerializer baseSerializer = (CodeDomSerializer)manager.GetSerializer(typeof(BaseUserControl).BaseType, typeof(CodeDomSerializer));
            return baseSerializer.Deserialize(manager, codeObject);
        }
    }

    public class MyCustomComponentResourceManager : ComponentResourceManager
    {
        public MyCustomComponentResourceManager() : base()
        {

        }

        public MyCustomComponentResourceManager(Type type) : base(type)
        {

        }
    }

You can swap the ComponentResourceManager with your own one. This way, you can get your images from the database at runtime. The designer will still generate the .resx files with the images and everything else inside it, but it's not a problem since, at design time, you still want to show some default images and whatnot. If you don't like the .resx files, I think you can define your own implementation with the IResourceService and save your stuff to a database instantly, but I didn't test it. So I might be wrong. I had a similar problem, but with localization. If you are interested, you can read my answer Here. Note that the form designer only works with the BASE class. You need to inherit the BaseUserControl to make the custom CodeDomSerializer work. The BaseUserControl still uses the "old" CodeDomSerializer. Last I recommend that you read this answer about how the Designer works Here