2013-01-02 7 views
8

Ich habe eine benutzerdefinierte Implementierung eines Blocks, der ähnlich wie Html.BeginForm() funktioniert. Die Umsetzung ist im Grunde wie folgt:Razor: benutzerdefinierte BeginForm() - wie Razor Einweg-Block funktioniert nicht in einigen Fällen

public class MyBlock : IDisposable { 
    private readonly HtmlHelper _html; 

    public MyBlock(HtmlHelper hml) { 
     this._html.ViewContext.Writer.WriteLine("BEGIN"); 
    } 

    public void Dispose() { 
     this._html.ViewContext.Writer.WriteLine("END"); 
    } 
} 

Dann meiner Meinung nach was ich tun kann:

@using (new MyBlock(Html)) { 
    @: some content 
} 

Um:

BEGIN 
some content 
END 

Das alles funktioniert gut. Ich gerate jedoch in Schwierigkeiten, wenn ich meinen Block in einem "Rasierschnipsel" benutze, z. G. wenn man etwas Rasierklingen-Inhalt an eine Funktion übergibt, die ein Func<object, HelperResult> als ein Argument nimmt. Zum Beispiel habe ich eine andere Htmlhelper Funktion wie folgt definiert:

public static IHtmlString Content(this HtmlHelper @this, Func<object, HelperResult> razor) { 
    return razor(null); 
} 

@* use in a view as: *@ 
@{ 
    var razorContent = Html.Content(@<div>Some razor content</div>); 
} 
@razorContent 

Wenn ich die folgenden Code, wenn der innere Gehalt ohne den äußeren Inhalt rendert:

@{ 
    var content =Html.Content(
     @<text> 
      @using (new MyBlock(Html)) { 
       @: some content 2 
      } 
     <text> 
    ); 
} 
@content 

ich glaube, das Problem ist, dass " Html "bezieht sich immer noch auf den HtmlHelper des äußeren Kontextes und somit werden BEGIN und END an einen anderen Schreiber als" einige Inhalte 2 "gesendet, ich bin mir jedoch nicht sicher, dass dies der Fall ist.

Weiß jemand (1) was schief läuft und (2) wie ich es beheben kann?

Antwort

2

Teil Lösung Ihres Problems ist WriteTo Methode von HelperResult aufrufen.

public static void Content(this HtmlHelper @this, Func<object, HelperResult> razor) 
{ 
    razor(null).WriteTo(@this.ViewContext.Writer); 
} 

und dann auf diese Weise verwenden: Sie können Content-Methode, um so etwas wie dies ändern

@{ Html.Content(
     @<text> 
      @using (new MyBlock(Html)) { 
       @: some content 2 
      } 
     </text> 
    ); 
} 

EDIT

Wenn Sie Wert als IHtmlString zurückkehren möchten oder eine andere Zeichenfolge kann das tun:

public static IHtmlString Content(this HtmlHelper @this, Func<object, HelperResult> razor) 
{ 
    using (MemoryStream ms = new MemoryStream()) 
    using (TextWriter tw = new StreamWriter(ms)) 
    { 
     Delegate @delegate = (Delegate)razor; 
     WebViewPage target = (WebViewPage)@delegate.Target; 
     TextWriter tmp = target.Html.ViewContext.Writer; 
     try 
     { 
      target.Html.ViewContext.Writer = tw; 
      razor(null).WriteTo(tw); 
      tw.Flush(); 
      ms.Seek(0, SeekOrigin.Begin); 
      TextReader tr = new StreamReader(ms); 

      return MvcHtmlString.Create(tr.ReadToEnd()); 
     } 
     finally 
     { 
      target.Html.ViewContext.Writer = tmp; 
     } 
    } 
} 
+0

Mein Ziel ist es, die Inhaltsvariable in einem HTMLString zu erfassen, die dann woanders übergeben werden können. Es sieht nicht so aus, als ob das das Problem löst, oder? – ChaseMedallion

0

Das hat mich schon seit einiger Zeit beunruhigt. Es ist ein Rasierklingen-Fehler wegen MyBlock und der HtmlHelper mit verschiedenen Writern. Eine sinnvolle Lösung besteht darin, den __razor_template_writer von HtlmHelper in MyBlock zu übergeben. (Hoffentlich wird dies in vnext behoben werden)

public class MyBlock : IDisposable { 
    private readonly TextWriter _writer; 

    public MyBlock(TextWriter writer) { 
     _writer = writer; 
     _writer.WriteLine("BEGIN"); 
    } 

    public void Dispose() { 
     _writer.WriteLine("END"); 
    } 
} 

@{ 
    var content =Html.Content(
     @<text> 
      @using (new MyBlock(__razor_template_writer)) { 
       @: some content 2 
      } 
     <text> 
    ); 
} 
@content