views:

515

answers:

2

Let's say I have a string that I retrieve from a DB like:
"Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et {{Hyperlink|navigateurl='/foo.aspx'}} dolore magna aliquyam."

This string may now get assigned to the Text-property of a label.
What I want is to parse {{Hyperlink|navigateurl='/foo.aspx'}} and replace it with

<asp:HyperLink ID="IDLink" runat="server" Text="foo" NavigateUrl="/foo.aspx"/>

and assign the whole text including the HyperLink-Control to the Label.

Is that even possible? I think I could use reflection to create the control and set the properties. (the HyperLink-Control was just an example) But can I manage to insert the asp.net control back into the string to ensure the hyperlinks rendering as server contorl?

I hope you understand what I want. If not, feel free to post comments.

Edit1:

what do you mean by "assign the whole text including the HyperLink-Control to the Label."? can you explain a bit, the reason for doing so ?

I think it won't work to assign the control into the string, because a asp.net control cannot be fit into a string.

After some thinking I found a way to achieve my goal. That would be to create a placeholder (I name it A). Therein some Literal control will be added. In addition I would create a placeholder (I name it B), add my Hyperlink into B, and add A into B. But I think is way to overkill.

The reason why I started thinking about this, was to gain access to Server.MapPath without replacing occurences in the string. I want to be able to use relative paths in my CMS, that get rendered like the NavigateUrl property from a hyperlink. Nevertheless I think my question with the dynamically creation is worth thinking about

+1  A: 

I believe this is possible if you split your text into 2 labels instead of one. I wrote up a quick sample to demonstrate. When you parse your string from the db, if there is text before and after your dynamic control than just set the BeginText and EndText properties of DynamicControl.

public class DynamicControl
{
    public String BeginText { get; set; }
    public String EndText { get; set; }
    public String ControlName { get; set; }
    public Dictionary<String, String> ControlProperties { get; set; }
}

public partial class _Default : System.Web.UI.Page 
{
    protected override void OnInit(EventArgs e)
    {
        base.OnInit(e);
        //read strings from db
        var dynamicControlStrings = GetStringsFromDB();
        //parse strings into list of dynamicControls
        var dynamicControls = ParseStringsToDynamicControls(dynamicControlStrings);
        foreach (var dynamicControl in dynamicControls)
        {
            CreateControl(dynamicControl.BeginText, dynamicControl.EndText, dynamicControl.ControlName, dynamicControl.ControlProperties);
        }
    }

    private void CreateControl(string beginText, string endText, string controlName, Dictionary<String, String> controlProperties)
    {
        var beginLabel = new Label()
        {
            Text = beginText
        };

        var dynamicControl = GenerateDynamicControl(controlName, controlProperties);        

        var endLabel = new Label()
        {
            Text = endText
        };

        var span = new HtmlGenericControl("span");
        span.Controls.Add(beginLabel);
        span.Controls.Add(dynamicControl);
        span.Controls.Add(endLabel);

        form1.Controls.Add(span);        
    }

    //you would create your dynamic control here (such as the hyperlink) based on the control name and use reflection to set the properties
    private WebControl GenerateDynamicControl(string controlName, Dictionary<String, String> controlProperties)
    {        
    }

    protected void Page_Load(object sender, EventArgs e)
    {

    }    
}
Matt Dearing
Yep, somethink like that came into my mind. What do you think, how efficient will this be?
citronas
Reflection is definitely slower than direct access of some object but I think this blog post sums up a lot of the common misconceptions http://www.west-wind.com/weblog/posts/351.aspx. I assume you arn't going to be auto-generating hundreds of thousands of controls per page, so you should be fine. You might want to think about your dynamic control token though. If you are planning on using something like Activator.CreateInstance(...) you will want to have the full type name in your token to make things easier on yourself.
Matt Dearing
+1  A: 
public class Program
    {
        static void Main(string[] args)
        {
            ParserBase parser = new ParserBase();

            Console.WriteLine(parser.DynamicRenderControl<HyperLink>(parser.Parse("")));
            Console.ReadLine();
        }
    }

    public class ParserBase
    {
        public virtual Dictionary<string, string> Parse(string stringToParse)
        {
            //...
            // parse the stringToParse
            //...
            Dictionary<string, string> parsedPropertiesValues = new Dictionary<string, string>();
            parsedPropertiesValues.Add("NavigateUrl", @"http://www.koolzers.net");
            return parsedPropertiesValues;
        }

        protected virtual void SetProperty<T>(T obj, string propertyName, string value) where T : WebControl
        {
            typeof(T).GetProperty(propertyName).SetValue(obj, value, null);
        }


        public string DynamicRenderControl<T>(Dictionary<string, string> parsedPropertiesValues) where T : WebControl, new()
        {
            StringBuilder sb = new StringBuilder();
            using (T control = new T())
            {
                foreach (KeyValuePair<string, string> keyValue in parsedPropertiesValues)
                {
                    SetProperty<T>(control, keyValue.Key, keyValue.Value);
                }

                using (StringWriter tw = new StringWriter(sb))
                {
                    using (HtmlTextWriter w = new HtmlTextWriter(tw))
                    {
                        control.RenderControl(w);
                    }
                }

            }
            return sb.ToString();
        }
    }
igor
Nice one. Haven't though of rendering the subcontrol and adding the html output back into the string.
citronas
You are a genius ;)
citronas