Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Jeroen Breuer 4908 posts 12265 karma points MVP 4x admin c-trib
    Jun 29, 2011 @ 08:57
    Jeroen Breuer
    0

    Set Razor macro parameters in code behind

    Hello,

    I've got a Razor macro and I want to set some parameters in the code behind. Is this possible because I can't get it to work yet.

    Here is my Razor code:

    <p>This is a test</p>
    @Parameter.Field

    Here is my marco:

    <umbraco:Macro ID="SearchResults" runat="server" filelocation="~/macroScripts/portal/search.cshtml"/>

    Now I'm trying to set my field in the code behind:

    protected override void OnInit(EventArgs e)
    {
        base.OnInit(e);
    
        SearchResults.MacroAttributes["Field"] = "object";
        SearchResults.Attributes["Field"] = "object";
    }

    This doesn't work and the razor code doesn't render @Parameter.Field.

    If I try this it works, but that's not how I want to set my parameters.

    <umbraco:Macro ID="SearchResults" runat="server" filelocation="~/macroScripts/portal/search.cshtml" Field="test"/>

    Anyone know how I can do this?

    Jeroen

  • Stephen 767 posts 2273 karma points c-trib
    Jun 29, 2011 @ 09:01
    Stephen
    0

    Have you tried doing on on PreInit?

  • Jeroen Breuer 4908 posts 12265 karma points MVP 4x admin c-trib
    Jun 29, 2011 @ 09:06
    Jeroen Breuer
    0

    I'm using a usercontrol and it doesn't seem I can override the PreInit there.

  • Gareth Evans 142 posts 334 karma points c-trib
    Jun 29, 2011 @ 09:25
    Gareth Evans
    0

    Try PreRender as well

    Are you getting an error, or is it just not showing you the value?

    Pretty sure this won't be possible easily

  • Jeroen Breuer 4908 posts 12265 karma points MVP 4x admin c-trib
    Jun 29, 2011 @ 09:33
    Jeroen Breuer
    0

    I'm not getting an error. Just don't see any values. PreRender also doesn't seem to work. Any hint where I have to look to make this work?

    Jeroen

  • Sebastiaan Janssen 5045 posts 15477 karma points MVP admin hq
    Jun 29, 2011 @ 09:39
    Sebastiaan Janssen
    0

    I just found this link the other day, it might help you out.

  • Jeroen Breuer 4908 posts 12265 karma points MVP 4x admin c-trib
    Jun 29, 2011 @ 11:29
    Jeroen Breuer
    0

    Thanks for the tip Sebastiaan, but it's still not solved :(

    This now works:

    <umbraco:Macro ID="SearchResults" runat="server" filelocation="~/macroScripts/portal/search.cshtml" Field="<%$ Code: DateTime.Now.ToString() %>"/>

    But here is some code that doesn't work yet.

    The front code:

    <asp:TextBox ID="TxtField" runat="server"></asp:TextBox>
    <asp:Button ID="BtnSend" runat="server" Text="Click" />
    <umbraco:Macro ID="SearchResults" runat="server" filelocation="~/macroScripts/portal/search.cshtml" Field="<%$ Code: PropTest %>"/>

    The code behind:

    public string PropTest
    {
        get
        {
            return "another test " + TxtField.Text;
        }
    }
    
    protected void Page_Load(object sender, EventArgs e)
    {
    }

    I want to enter a value in the textfield, post the value and than pass it to the macro. Unfortunately when the property get's called TxtField.Text is still empty, because it's not availble yet. If I hit the Page_Load method TxtField.Text is filled, but that's too late since the property already got called. 

    What's the best way to pass a value from a textbox webcontrol to the razor code? 

    My goal eventually is to create a DynamicNodeList in the code behind and pass that as a parameter to the macro. Is that possible?

    Jeroen

  • Stephen 767 posts 2273 karma points c-trib
    Jun 29, 2011 @ 12:26
    Stephen
    0

    The umbraco:Macro control renders the macro while in the OnInit event. So you have to populate the parameters _before_ that happens, using the Code expression trick. But then, this probably means that you are populating the parameters _before_ the post-back logic has run, and so TxtField.Text is still empty.

    You'll have to manually parse Request.Form and Request.QueryString and not rely on ASP.NET post-back logic, to read your form data.

    (But I do not understand why the umbraco:Macro control works this way... it does not seem too difficult to change it... although that would probably break backward compatibility for some sites?...)

  • Stephen 767 posts 2273 karma points c-trib
    Jun 29, 2011 @ 12:44
    Stephen
    2

    @Jeroen: I am looking at umbraco:Macro control code. The macro is rendered during OnInit so that, should the macro output some child controls (input fields...) they would be ready and in place to receive postback data. But does that make any sense? Does anybody actually does this?

    Because then it seems rather easy to create an umbraco:LateMacro that would render only during OnRender, allowing you to do what you want? You could try using this simple control:

        public class Macro : umbraco.presentation.templateControls.Macro
        {
            protected override void OnInit(EventArgs e)
            {
                // assuming it is safe not to call Control.OnInit...
            }
        }
  • Sebastiaan Janssen 5045 posts 15477 karma points MVP admin hq
    Jun 29, 2011 @ 14:36
    Sebastiaan Janssen
    0

    I've always been pretty bad at understanding the page lifecycle, so I can't be of much help there. Just a quick question though: why do you need to create the DynamicNodeList in codebehind? It can come from anywhere you want, so you could also write a little class that gives back the DynamicNodeList when you ask for it.

  • Jeroen Breuer 4908 posts 12265 karma points MVP 4x admin c-trib
    Jun 29, 2011 @ 15:05
    Jeroen Breuer
    1

    @Stephen Your suggestion works :). I created a custom Macro in which I simply disable the OnInit and it still works but everything is done in OnPreRender. Now this code works:

    protected void Page_Load(object sender, EventArgs e)
    {
        dynamic nodes = GetNodes();
    
        RenderMacro macro = (RenderMacro)this.FindControl("SearchResults");
        macro.MacroAttributes["Field"] = TxtField.Text;
    
        HttpContext.Current.Items["SearchResults"] = nodes;
    }

    The only problem is that if I pass my DynamicNodeList as a parameter I don't get the nodes in razor, but simple a string. So now I pass them into HttpContext.Current.Items["SearchResults"] and it just works. Here is my Razor code:

    <p>This is a test</p>
    @Parameter.Field<br />
    dynamic nodes = HttpContext.Current.Items["SearchResults"];
    foreach(dynamic d in nodes)
    {
        @d.typeName
    }

    Now I can build my DynamicNodeList in the code behind and I can render it in Razor :).

    @Sebastiaan I'm having a usercontrol in which I have some webcontrols (textboxes and checkboxes). In the code behind of the usercontrol it's very easy to retrieve the values of those webcontrols. I can than pass those values into a method which returns my DynamicNodeList which I can now pass to Razor :). It's kind of neat.

    Jeroen

  • Stephen 767 posts 2273 karma points c-trib
    Jun 29, 2011 @ 15:41
    Stephen
    0

    Cool! I still wonder why macros are rendered in OnInit... will try to figure out. And in any case this could be handled in the Core. We could add either a "LateMacro" control or a run="late" parameter...

  • Gareth Evans 142 posts 334 karma points c-trib
    Jun 29, 2011 @ 23:07
    Gareth Evans
    1

    RenderEvent="PreRender" or RenderEvent="Init" (default) makes more sense IMO, but I agree, it's an edge case but when you get burned by it, it's hard to work around

    I will put this into my "things to look into" list

     

    Gareth

  • Stephen 767 posts 2273 karma points c-trib
    Jun 30, 2011 @ 09:25
    Stephen
    1

    Currently running a patched Umbraco w/ new RenderEvent attribute. Supports Init, PreRender, Render and defaults to Init. I've tried running an entire site while defaulting to Render and it seems OK although further testing might be required to identify dirty side-effects.

    Could submit the patch... but no time to create a fork + pull request + etc at the moment :-( Maybe later today or tomorrow.

  • Gareth Evans 142 posts 334 karma points c-trib
    Jun 30, 2011 @ 22:55
    Gareth Evans
    0

    Awesome, if you do a fork+pull, i'll make note of it and pull it across before 4.7.1

  • Stephen 767 posts 2273 karma points c-trib
    Jul 14, 2011 @ 11:05
    Stephen
    1

    I have added the patch to 4.7.1 so now you can do <umbraco:Macro renderEvent="Render" ... />

  • Nick 101 posts 123 karma points
    May 23, 2012 @ 11:53
    Nick
    0

    I am having a lot of problems with this.

    My razor scripts outputs very intricate conditional markup and I want the .NET control to appear in a very specific part of the page so that's why I need to render it within the razor script.

    First of all I checked that the control works well if it's added in the template, but it appears at the very bottom of the page that way.

    If I write:

    @Html.Raw(umbraco.library.RenderMacroContent("<?UMBRACO_MACRO macroAlias=\"MyControl\" ></?UMBRACO_MACRO>",Model.Id))  

    the error I get is:

     Error generating macroContent: 'System.Web.HttpException (0x80004005): HtmlForm cannot render without a reference to the Page instance.  Make sure your form has been added to the control tree.
       at System.Web.UI.HtmlControls.HtmlForm.Render(HtmlTextWriter output)
       at System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter)
       at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
       at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
       at umbraco.presentation.templateControls.Macro.Render(HtmlTextWriter writer)
       at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)    at umbraco.library.RenderMacroContent(String Text, Int32 PageId)'

       I have checked that Model.Id is correct and not empty or null. 

    Someone said wrapping the razor in a <form runat="server"> but I cannot do that because the control includes that and we can't have a form within a form.

    The control itself only contains a textbox and a button with an onClick event that fires an email, it's a super simple control.

    Any ideas? 

    If it's infeasible with umbraco this way, what other way is there of doing this?
     

     

  • Jeroen Breuer 4908 posts 12265 karma points MVP 4x admin c-trib
    May 23, 2012 @ 11:58
    Jeroen Breuer
    0

    What do you mean that you can't add <form runat="server">? Best way is to have 1 <form runat="server"> for the entire page. Forms in forms don't work, but you don't have to if it's just 1 for the entire page.

    Jeroen

  • Nick 101 posts 123 karma points
    May 23, 2012 @ 12:04
    Nick
    0

    I don't think it matters if the form wraps the entire page or just the form I want posted so my problem wouldn't go away if I restructred all my templates and rewrote my .NET control. 

  • Gareth Evans 142 posts 334 karma points c-trib
    May 23, 2012 @ 23:38
    Gareth Evans
    0

    It appears to me that umbraco.library.RenderMacroContent is at fault here,

    I've checked the source for library.renderMacroContent - it should have a valid page but I can't speak for what your control itself is doing during render.

    Is there any way that this could be isolated into a test case for debugging?

Please Sign in or register to post replies

Write your reply to:

Draft