I have a server control that has a PlaceHolder that is an InnerProperty. In the class when rendering I need to get the text / HTML content that is supposed to be in the PlaceHolder. Here is a sample of what the front end code looks like:
<tagPrefix:TagName runat="server">
<PlaceHolderName>
Here is some sample text!
</PlaceHolderName>
</tagPrefix:TagName>
This all works fine except I do not know how to retrieve the content. I do not see any render methods exposed by the PlaceHolder class. Here is the code for the server control.
public class TagName : CompositeControl
{
[TemplateContainer(typeof(PlaceHolder))]
[PersistenceMode(PersistenceMode.InnerProperty)]
public PlaceHolder PlaceHolderName { get; set; }
protected override void RenderContents(HtmlTextWriter writer)
{
// i want to retrieve the contents of the place holder here to
// send the output of the custom control.
}
}
Any ideas? Thanks in advance.
I just found the solution. I did not see the render methods because of the context of how I was using the PlaceHolder object. Eg I was trying to use it as a value and assign it to a string like so:
string s = this.PlaceHolderName...
Because it was on the right hand side of the equals Intellisense did not show me the render methods. Here is how you render out a PlaceHolder using and HtmlTextWriter:
StringWriter sw = new StringWriter();
HtmlTextWriter htw = new HtmlTextWriter(sw);
this.PlaceHolderName.RenderControl(htw);
string s = sw.ToString();
Posting this as a second answer so I can use code formatting. Here is an updated method that uses Generics and also uses the 'using' feature to automatically dispose the text / html writers.
private static string RenderControl<T>(T c) where T : Control, new()
{
// get the text for the control
using (StringWriter sw = new StringWriter())
using (HtmlTextWriter htw = new HtmlTextWriter(sw))
{
c.RenderControl(htw);
return sw.ToString();
}
}
Related
TLDR; Please either confirm that the 2nd code snippit is the accepted method for creating a CustomXmlPart or show me another less tedious method.
So I'm trying to embed some application data in some of the elements in a .pptx that I'm modifying using the OpenXmlSDK.
To explain briefly, I need to embed an chart code into each image that is loaded into the presentation. It's so that the presentation can be re-uploaded and the charts can be generated again then replaced using the newest data.
Initially I was using Extended Attributes on the OpenXmlElement itself:
//OpenXmlDrawing = DocumentFormat.OpenXml.Drawing
// there's only one image per slide for now, so I just grab the blip which contains the image
OpenXmlDrawing.Blip blip = slidePart.Slide.Descendants<OpenXmlDrawing.Blip>().FirstOrDefault();
//then apply the attribute
blip.SetAttribute(new OpenXmlAttribute("customAttribute", null, customAttributeValue));
The issue with that being, when the .pptx is edited in PowerPoint 2013, it strips out all the Extended Attributes.
SO.
I've read in multiple places now that the solution is to use a CustomXmlPart.
So I was trying to find how to do it.. and it was looking like it would require me to have a separate file for each CustomXmlPart to feed into the part. Ex/
var customXmlPart = slidePart.AddCustomXmlPart(CustomXmlPartType.CustomXml);
using (FileStream stream = new FileStream(fileName, FileMode.Open))
{
customXmlPart.FeedData(stream);
}
^ and that would need to be repeated with a different file for each CustomXmlPart. Which then means I'd likely just have to have a template file containing a skeleton custom XML part, and then dynamically fill in its contents for each individual slide before feeding it into the custom xml part.
It seems like a heck of a lot of work just to put in a little custom attribute. But I haven't been able to find any alternative methods.
Can anyone please either confirm that this is indeed the way I should do it, or point me in another direction? Greatly appreciated.
The answer is yes! :)
public class CustomXMLPropertyClass
{
public string PropertyName { get; set; }
public string PropertyValue { get; set; }
}
private static void AddCustomXmlPartCustomPropertyToSlidePart(string propertyName, string propertyValue, SlidePart part)
{
var customXmlPart = part.AddCustomXmlPart(CustomXmlPartType.CustomXml);
var customProperty = new CustomXMLPropertyClass{ PropertyName = propertyName, PropertyValue = propertyValue };
var serializer = new System.Xml.Serialization.XmlSerializer(customProperty.GetType());
var stream = new MemoryStream();
serializer.Serialize(stream, customProperty);
var customXml = System.Text.Encoding.UTF8.GetString(stream.ToArray());
using ( var streamWriter = new StreamWriter(customXmlPart.GetStream()))
{
streamWriter.Write(customXml);
streamWriter.Flush();
}
}
and then to get it back out:
private static string GetCustomXmlPropertyFromCustomXmlPart(CustomXmlPart customXmlPart)
{
var customXmlProperty = new CustomXMLPropertyClass();
string xml = "";
using (var stream = customXmlPart.GetStream())
{
var streamReader = new StreamReader(stream);
xml = streamReader.ReadToEnd();
}
using (TextReader reader = new StringReader(xml))
{
var serializer = new System.Xml.Serialization.XmlSerializer(typeof(customXmlProperty));
customXmlProperty = (CustomXMLPropertyClass)serializer.Deserialize(reader);
}
var customPropertyValue = customXmlProperty.PropertyValue;
return customPropertyValue;
}
You could also try custom properties. Custom XML files are meant for complex objects, and it sounds like you only need to store simple information.
I have been stuck on this problem for the last 2 days and still haven't made it work and I am looking for some help.
My Listbox gets generated items added to it depending on the item selected in the Combobox. When I click the button Create a new Window appears with a WebBrowser object inside of it.
(Wasnt allowed to upload image so it is contained in the link)
This is the screen with the list box with the items generated and also the button that is clicked.
http://imgur.com/6B8GO1m
Button Click Event
This gets the item selected in the Combobox. Then it creates a new instance of the Alrighty Class with the property called Standards with the List of items (The items from the Listbox). The property gets populated with the third line and then I have another class named SaveXML (See Below) and this saves in XML. Then will open the browser.
string selectedStandard = (string)cmbStandard.SelectedItem;
Alrighty info = new Alrighty();
info.Standards = _standardDefinitions;
SaveXML.SaveData(info, string.Format("{0}.xml", selectedStandard));
HTMLBrowser boss = new HTMLBrowser(selectedStandard);
boss.Show();
SaveXML Class
public static void SaveData(object obj, string filename)
{
XmlSerializer sr = new XmlSerializer(obj.GetType());
TextWriter writer = new StreamWriter(filename);
sr.Serialize(writer, obj);
writer.Close();
}
The Problem
When I click the button and get onto the Window with the Web Browser on this code appears:
http://imgur.com/zF465n5
As you can see from the blue box, When I delete this code and add the code in for my Stylesheet everything works fine, but the problem is the code in the blue box keeps getting generated, is there a way to not get this code in the XML file that is created.
Extra
How can I get this string to appear instead of the generated code in the blue box:
<?xml-stylesheet type="text/xsl" href="StandardXS.xsl"?>
EDIT:
public class SaveXML
{
public static void SaveData(object obj, string filename)
{
//empty namespace and empty value
XmlSerializerNamespaces alright = new XmlSerializerNamespaces();
alright.Add("", "");
XmlSerializer sr = new XmlSerializer(obj.GetType());
TextWriter writer = new StreamWriter(filename);
sr.Serialize(writer, obj, alright);
writer.Close();
}
public void WriteXml(XmlWriter writer) { writer.WriteAttributeString(#"<?xml-stylesheet type=text/xsl href=StandardXS.xsl?>", string.Empty); }
}
You can do it like this:
XmlSerializerNamespaces namespace = new XmlSerializerNamespaces();
//empty namespace and empty value
namespace.Add("", "");
XmlSerializer serializer = new XmlSerializer(someType);
//Serialize the object with custom namespace
serializer.Serialize(xmlTextWriter, myObj, namespace);
For adding a custom attribute, as I said in the comments, implement IXmlSerializable and implement WriteXml and add your custom attribute.
There are lots of examples on the web of transforming an XML file to a different format using an XSLT file, like the following:
XslTransform myXslTransform = new XslTransform();
XsltSettings myXsltSettings = new XsltSettings();
myXsltSettings.EnableDocumentFunction = true;
myXslTransform.Load("transform.xsl");
myXslTransform.Transform("input.xml", "output.xml");
However this is only a partial answer, I would like to be able to get the XML input data from a web form and use that as the input xml data instead of an '.xml' file, but have not found any concrete examples. Using Visual Studio I see Load methods that accept XmlReader objects as parameters but I do not know how to create one of those using the data from a form and TextBox control. It would be very helpful if someone could provide an example of transforming XML using form data instead of an input file.
Create a class and populate an instance of this class during postback from your form data and serialize it ( convert it to xml)
Here is console example for you
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
namespace Stackoverflow
{
public class Program
{
static void Main(string[] args)
{
var p = new Person
{
FirstName = "Daniel", /// in your case you get it from the form
LastName = "Endeg"
};
var x = new XmlSerializer(p.GetType());
x.Serialize(Console.Out, p);
Console.WriteLine();
Console.ReadLine();
}
}
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
}
Please note that XslTransform is obsolete since .NET 2.0, you should use XslCompiledTransform instead. And if you want to use XslSettings then make sure you pass them in to the XslCompiledTransform's Load method (e.g. http://msdn.microsoft.com/en-us/library/ms163425.aspx), simply creating it does not make sense.
As for parsing XML you have in a string variable or property (like the Text property of a TextBox) you have lots of options, you can use an XmlReader over a StringReader e.g.
XslCompiledTransform proc = new XslCompiledTransform();
proc.Load("sheet.xsl");
using (StringReader sr = new StringReader(TextBox1.Text))
{
using (XmlReader xr = XmlReader.Create(sr))
{
proc.Transform(xr, null, Response.Output);
}
}
Or you can create an XPathDocument or XmlDocument or XDocument from the string and use an overload of the Transform method that takes an IXPathNavigable as the first argument.
Ok, with some help from Visual Studio auto-complete which lists the parameters for constructors and methods, I was able to complete a working answer to the problem above, using strings for input and output in an Xslt transform operation. Yay. The example answer below assumes you have three strings containing the Xslt text data and the input Xml text data and output Xml data:
string XsltText;
string InputXML;
string OutputXml;
// define the xslt from a string
TextReader myXsltText = new StringReader(XsltText);
XmlReader myXslt = new XmlTextReader(myXsltText);
// define the input xml from a string
TextReader myXmlText = new StringReader(InputXML);
XmlReader myInputXml = new XmlTextReader(myXmlText);
// define the output XmlWriter for the results of the transform
TextWriter myOutputXmlTextWriter = new StringWriter();
XmlWriter myOutputXml = new XmlTextWriter(myOutputXmlTextWriter);
XslCompiledTransform myXslTransform = new XslCompiledTransform();
XsltSettings myXsltSettings = new XsltSettings();
myXsltSettings.EnableDocumentFunction = true;
myXslTransform.Load(myXslt);
myXslTransform.Transform(myInputXml, myOutputXml);
// the result from the transform comes from the TextWriter object
OutputXml = myOutputXmlTextWriter.ToString();
// clean up writers
myOutputXml.Flush();
myOutputXmlTextWriter.Close();
myOutputXml.Close();
To get this code working with a web form, all you have to do is get the strings from the value (Text) of the form elements (controls), for the input XMl and Xslt you could use TextBox controls, and to display the results you could use a label, all very useful, if anyone has a better answer please feel free to let me know.
In ASP.NET, is it possible to get the values of __VIEWSTATE and __EVENTVALIDATION hidden fields into a variable in C# (server side) in, let's say, overriding the Render method?
I have tried:
protected override void Render(HtmlTextWriter writer)
{
StringBuilder stringBuilder = new StringBuilder();
StringWriter stringWriter = new StringWriter(stringBuilder);
HtmlTextWriter htmlWriter = new HtmlTextWriter(stringWriter);
base.Render(htmlWriter);
string temp = stringBuilder.ToString();
}
This gives me the entire ASP.NET output. We can get the values by using a string function, but I did not find it a very clean solution. Is there a better way to do this?
What I actually want is the values of __VIEWSTATE & __EVENTVALIDATION when the first request is made and not after the postback is done. That is when the output stream if formed when the first request is made.
If you look at the Page class using Reflector, you'll see these hidden fields are created during the render phase (look at the methods RenderViewStateFields and EndFormRenderHiddenFields).
You could probably get at some/all of the data using reflection (e.g. the internal property Page.ClientState).
But I don't think there is a clean solution (though to be honest I don't really understand what you're trying to achieve).
To get the event validation you should use HTML Agility Pack.
var eventValidation = HapHelper.GetAttributeValue(htmlDocPreservation, "__EVENTVALIDATION", "value");
public static string GetAttributeValue(HtmlDocument doc, string inputName, string attrName)
{
string result = string.Empty;
var node = doc.DocumentNode.SelectSingleNode("//input[#name='" + inputName + "']");
if (node != null)
{
result = node.Attributes[attrName].Value;
}
return result;
}
How would you create a new DropDownList (or any asp server control) and then render the html to a string in C#?
System.Web.UI.Control has a RenderControl(HtmlTextWriter) method that you can use to get the rendered content of the control as a string:
using(var sw = new System.IO.StringWriter()) // SW is a buffer into which the control is rendered
using(var writer = new HtmlTextWriter(sw))
{
myControl.RenderControl(writer);
return sw.ToString(); // This returns the generated HTML.
}