Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to update design-time UserControl interface based on property value?

I've created a UserControl with the following public property:

[Browsable(true)]
public string Text
{
    get { return pnlLookupTable.GroupingText; }
    set { pnlLookupTable.GroupingText = value; }
}

pnlLookupTable is, as you may have guessed, a Panel control. I can change the value of the Text property in the Properties window and it's reflected in the markup like it should be. However, the design view of the UserControl inside a page does not show updated GroupingText for the Panel. How can I get this to happen?

EDIT:

By request, here is the entire class to which that property belongs. You can see there's nothing special going on:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class LookupTable : System.Web.UI.UserControl
{
    [Browsable(true)]
    public string Text
    {
        get { return pnlLookupTable.GroupingText; }
        set { pnlLookupTable.GroupingText = value; }
    }
}

And here's the relevant part of the .ascx file:

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="LookupTable.ascx.cs" Inherits="LookupTable" %>
<asp:Panel ID="pnlLookupTable" runat="server" GroupingText="Lookup Table">
    <%-- Irrelevant content here. --%>
</asp:Panel>

I have changed some identifiers and other trivial things to protect the proprietary nature of the code.

I should also reiterate that I'm looking at a Web form in design mode that has my control added, and I'm changing the Text property. I want to see the change to the Panel's GroupingText visually in the designer.

like image 744
Andy West Avatar asked Jan 14 '10 05:01

Andy West


2 Answers

I'd have to think back a bit to the UserControlDesigner code...

Short story: I don't think it's possible.

And here's the long story:

From what I recall, User Controls located in ASCX files are never run in the designer. That is, the code inside the ASCX or ASCX.CS file is never compiled or run in Visual Studio. This is to prevent memory leaks caused by the fact that in the CLR you cannot unload assemblies that you have loaded. In order to run the code in your User Control, Visual Studio would have to compile your ASCX into a DLL, then load it, and then run the code. Every time you make a change to the ASCX, it would have to perform this operation again. Every time this operation happens more memory will be consumed by the additionally loaded DLL generated from your ASCX.

Because of this limitation in the CLR the User Control designer doesn't actually compile or run the ASCX file. Instead, it parses the ASCX file and looks for controls inside it and it loads those controls instead. For each control it finds in the ASCX file it will create the associated control designer and render that control's design time HTML.

There are a couple of ways to work around this:

  1. Instead of using an ASCX user control you can write a regular custom control that derives from Control and the code is written in a CS or VB file.
  2. Compile the ASCX into a DLL. David Ebbo wrote a blog post on how to do this.

The reason that these two solutions should work is that they both involve having the code compiled into a DLL. The idea is that the DLL doesn't change very often so it is safe for Visual Studio to load the DLL without risk of having to reload it for each time the DLL changes (and leak memory).

like image 69
Eilon Avatar answered Nov 02 '22 18:11

Eilon


I thought for sure I had an answer for this, and wrote it all out, but something was bugging me about it so I ended up testing this out for a few hours.

Turns out that (just like Eilon said), I don't think you can do this.

ASCX controls completely ignore the DesignerAttribute, so you can't specify a custom design time renderer for them. I thought "fine, I can subclass the Panel control and specify a new designer on it that will get properties from the parent control". Guess what? No chance. If you access the Panel's parent control in the designer, it will not cast to the custom usercontrol type. I can see that it's a UserControl, and it can't possibly be any other UserControl except my TestUserControl, but the designer class throws an exception if I try to cast it!

This blows my mind to be honest. It's basically exactly what Eilon is saying - there is an intentional restriction on web usercontrols in design mode.

Here's a vague post from Steven Cheng suggesting that design time support is just a no-go for web usercontrols.

While this was a fun learning opportunity for me, I'm sorry to report that I don't think an .ascx will cut it. I'm pretty sure that even compiling it to a DLL like Eilon suggested won't even do it. You'll probably have to go the custom control route.

like image 41
womp Avatar answered Nov 02 '22 19:11

womp