Update a canvas children from a saved txt file - c#

I am trying to update a canvas from xaml code that i have in a txt file.
What i have done is a save function that saves the canvas that surrounds everything.
Then i am trying to create a load function that opens that txt file and updates the canvas with the data from that file.
But my problem is that it do not update the existing canvas but instedd ad a new one so i have 2.
my question is how do i fix my load function so it do not add a new canvas but only adds the saved canvas children.
Right now my load function locks like this:
if (userClickedOK == true)
{
StreamReader sR = new StreamReader(dlg.FileName);
string text = sR.ReadToEnd();
sR.Close();
StringReader stringReader = new StringReader(text);
XmlReader xmlReader = XmlReader.Create(stringReader);
Canvas canvas1 = (Canvas)System.Windows.Markup.XamlReader.Load(xmlReader);
parentWindow.canvas.Children.Clear(); // clear the existing children
parentWindow.grid.Children.Add(canvas1);
Eddit: new code:
if (userClickedOK == true)
{
StreamReader sR = new StreamReader(dlg.FileName);
string text = sR.ReadToEnd();
sR.Close();
StringReader stringReader = new StringReader(text);
XmlReader xmlReader = XmlReader.Create(stringReader);
parentWindow.canvas = (Canvas)System.Windows.Markup.XamlReader.Load(xmlReader);
parentWindow.grid.Children.Add(parentWindow.canvas);
}
// Nivres

I believe i did solve it.
parentWindow.grid.Children.Remove(parentWindow.canvas);
parentWindow.canvas = (Canvas)System.Windows.Markup.XamlReader.Load(xmlReader);
parentWindow.grid.Children.Add(parentWindow.canvas);
With this i only get one Canvas, but maybe it is the wrong way to go.

Related

Is there a way to read a text file from resources without typing the file name?

using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("xyz.project.Folder1.Folder2.SomeFile.Txt"))
{
TextReader tr = new StreamReader(stream);
string fileContents = tr.ReadToEnd();
}
var html = File.ReadAllText(Properties.Resources.FilesTypes);
var html = File.ReadAllText(#"E:\New folder (44)\New Text Document.txt");
In the original and what is working i used the lastl ine:
var html = File.ReadAllText(#"E:\New folder (44)\New Text Document.txt");
But then i added the text file to my project resources since i want the file to be in the program all the time and not to read it from the hard disk.
Then i added the code with the assembly
Assembly.GetExecutingAssembly().GetManifestResourceStream("xyz.project.Folder1.Folder2.SomeFile.Txt"))
{
TextReader tr = new StreamReader(stream);
string fileContents = tr.ReadToEnd();
}
But in this case i need to type the name of the file manualy.
So i tried this line:
var html = File.ReadAllText(Properties.Resources.FilesTypes);
But getting exception:
Illegal characters in path

Open XML adding images in multiple picture content controls

ok, old question is gone and this is new one:
#JasonPlutext, we decided to do it the way you suggested. custom xml looks like:
<DATA>
<BLOCK>
<FNAME>Test</FNAME>
<LNAME>Test1</LNAME>
</BLOCK>
<PICTURE>
<SIG> domain\username</SIG>
</PICTURE>
</DATA>
Text controls are binded: $rowBlock.FNAME, $rowBlock.LNAME and picture content control is $rowPicture.SIG.
text from xml is displayed, but there is no picture...
Picture is returned by ws (web service input parameter is domain\username from <sig> and picture is returned as byte[]).
//this is part of code where dealing with picture content control
picture[] pic = getPic("domain\username");
Paragraph tP = new Paragraph();
ParagraphProperties tParagraphProperties =
pControl.Descendants<ParagraphProperties>).FirstOrDefault();
tP.ParagraphProperties = (ParagraphProperties)tParagraphProperties.Clone();
...?...
Please suggest what to do next and how to bind picture?
thx
You could consider a slightly different approach.
You can bind a picture content control to an element in a custom xml part which contains a base64 encoded image.
If you do it this way, you can rely on Word to resolve the binding (ie update the image on the document surface with the one in the custom xml part). Or you can mimic what Word does yourself; docx4j.NET contains code to do that for you.
Doing it this way becomes a matter of just updating the custom xml part with the images you want.
Jason, i'm injecting base64 encoded image content as you said, but there is still no picture. in customXml folder of zip document, in item3.xml there is a base64 string inside tag, but in media folder there is only default image. don't know what's wrong... my procedure is:
//first, searching for drawing inside current processing control
`Drawing tDraw = pControl.Descendants<Drawing>().FirstOrDefault();
//if there is a drawing element, then clone control
OpenXmlElement tClone = (OpenXmlElement)pControl.Clone();
//then call method:
private static void insertPicture(OpenXmlElement pControl)
{
//WordprocessingDocument wordDoc = WordprocessingDocument.Open(dokument, true);
MainDocumentPart mainPart = dokument.MainDocumentPart;
CustomXmlPart customPart = mainPart.CustomXmlParts.FirstOrDefault();
//convert image into string
string picName = #"c:\temp\picasso.png";
System.IO.FileStream fileStream = System.IO.File.Open(picName, System.IO.FileMode.Open);
System.IO.BinaryReader br = new System.IO.BinaryReader(fileStream);
byte[] byteArea;
byteArea = br.ReadBytes(System.Convert.ToInt32(fileStream.Length));
string picString = System.Convert.ToBase64String(byteArea);
//Load the XML template
string DataString = iData["DATA"].ToString();
//Properties.Resources.XMLData;
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(DataString);
//change the value
XmlNodeList xmlNode = xmlDoc.GetElementsByTagName("picture");
xmlNode[0].InnerText = picString;
//write the custom xml data into the customxmlpart
System.Xml.XmlTextWriter writer = new System.Xml.XmlTextWriter(customPart.GetStream(System.IO.FileMode.Create), System.Text.Encoding.UTF8);
writer.WriteRaw(xmlDoc.InnerXml);
writer.Flush();
writer.Close();
fileStream.Close();
br.Close();
mainPart.Document.Save();
//dokument.Close();
}
then append control to document
OpenXmlElement tC1 = pControl;
IEnumerable<Run> tEl1 = tClone.Descendants<Run>();
if (tEl1.Count() != 0)
{
foreach (OpenXmlElement tElement in tEl1.Reverse())
{
OpenXmlElement tClone1 = (OpenXmlElement)tElement.Clone();
tC1.InsertBeforeSelf(tClone1);
tC1 = tClone1;
}
}`

How to visualize XAML

I have a task to write down a simple viewer that would show how a .xaml file visually looks like(just like the VS editor, but without editing capabilities). Could you give me any references that would help me?
you can use XamlReader.Load method
If you want only viewer, not a designer you can call XamlReader.Load method, and assign the result to ContentControl.Content
StringReader stringReader = new StringReader(strXaml);
XmlReader xmlReader = XmlReader.Create(stringReader);
myContentControl.Content = (Button)XamlReader.Load(xmlReader);
EDIT
This code loads window from xaml and show it
string strXaml = "<Window xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" Title=\"MainWindow\" Height=\"350\" Width=\"525\">" +
"<Grid> <Button Content=\"Button123\" Height=\"23\" HorizontalAlignment=\"Left\" Margin=\"174,41,0,0\" Name=\"button1\" VerticalAlignment=\"Top\" Width=\"75\" />"+
"</Grid></Window>";
StringReader stringReader = new StringReader(strXaml);
XmlReader xmlReader = XmlReader.Create(stringReader);
Window obj = (Window)XamlReader.Load(xmlReader);
obj.Show();
If you are sure that the root element is allways Window, you can skip it. Something like this works for me
StringReader stringReader = new StringReader(strXaml);
var xDoc = XDocument.Load(stringReader).Document.Descendants().First().DescendantNodes().First();
XmlReader xmlReader = xDoc.CreateReader();
uc.Content = XamlReader.Load(xmlReader);
Would be better to check if Window exists or not before skipping it
You should start by looking at the XamlServices class and its Parse method.

getting "Stream Was Not Writable" while saving an XML document that I read via a stream from a zip file

I have a zip file that contains an xml file,
I'm Loading this xml file to an xml document without having to extract the file.
this is done via a stream.
after doing so, I'm modifying the inner text of some nodes.
The Problem is that I'm getting the previous mentioned exception after trying to save the stream, here's the code:
(I'm using DotNetZip here)
ZipFile zipFile = ZipFile.Read(zipPath); // the path is my desktop
foreach (ZipEntry entry in zipFile)
{
if (entry.FileName == "myXML.xml")
{
//creating the stream and loading the xml doc from the zip file:
Stream stream = zipFile[entry.FileName].OpenReader();
XmlReader xReader = XmlReader.Create(stream);
XmlDocument xDoc = new XmlDocument();
xDoc.Load(xReader);
//changing the inner text of the doc nodes:
xDoc.DocumentElement.SelectSingleNode("Account/Name").InnerText = "VeXe";
xDoc.DocumentElement.SelectSingleNode("Account/Money").InnerText = "Million$";
xDoc.Save(stream); // here's where I got the exception.
break;
}
}
I'm not a pro coder, but instead of xDoc.Save(stream); I noticed that it could also take a XmlWriter as a parameter, so I tried making an instance of the XmlWriter immediately after instantiating the XmlReader ..
I tried doing this: xDoc.Save(XmlWriter)
I got an exception saying something like: "Cannot Write After Reading"
how can I successfully save the xDoc ?
ADDED:
I had an idea of saving the xml file in some other place, like a temp folder or something
then adding that saved file in the zip overwriting the old one, then deleting the xml file in the temp ..
but that's not what i want, I want to deal directly with the zip file, in and out, no third parties.
You're attempting to write to the same Stream you've opened it with. You cannot do that.
Perhaps try something like this:
ZipFile zipFile = ZipFile.Read(zipPath); // the path is my desktop
foreach (ZipEntry entry in zipFile)
{
if (entry.FileName == "myXML.xml")
{
//creating the stream and loading the xml doc from the zip file:
using (Stream stream = zipFile[entry.FileName].OpenReader()) {
XmlReader xReader = XmlReader.Create(stream);
XmlDocument xDoc = new XmlDocument();
xDoc.Load(xReader);
}
//changing the inner text of the doc nodes:
xDoc.DocumentElement.SelectSingleNode("Account/Name").InnerText = "VeXe";
xDoc.DocumentElement.SelectSingleNode("Account/Money").InnerText = "Million$";
using (StreamWriter streamWriter = new StreamWriter(pathToSaveTo)) {
xDoc.Save(streamWriter);
break;
}
}
}
A quick look at the docs leads me to believe that you should do it something like this:
using(ZipFile zipFile = ZipFile.Read(zipPath))
foreach (ZipEntry entry in zipFile)
{
if (entry.FileName == "myXML.xml")
{
XmlDocument xDoc = new XmlDocument();
//creating the stream and loading the xml doc from the zip file:
using(Stream stream = zipFile[entry.FileName].OpenReader())
using(XmlReader xReader = XmlReader.Create(stream))
{
xDoc.Load(xReader);
}
//changing the inner text of the doc nodes:
xDoc.DocumentElement.SelectSingleNode("Account/Name").InnerText = "VeXe";
xDoc.DocumentElement.SelectSingleNode("Account/Money").InnerText = "Million$";
using(var ms=new MemoryStream())
using(var sw=new StreamWriter(ms))
{
xDoc.Save(sw);
sw.Flush();
ms.Position=0;
zipFile.UpdateEntry(entry.FileName,ms);
}
break;
}
}

Underline form field value using itextsharp

I have an application that uses itextsharp to fill PDF form fields.
I got new requirement from the customer to allow underlining the fields values.
I have read many posts including answers to questions in this site but I could't figure out a way to do it.
Current my code does the following:
Creates a PDFStamper instance
Get the form fields using stamper.AcroFields property
Set the field value using the AcroFields.SetFieldRichValue() method.
But when I am opening the PDF the field is empty.
I verified that the field is set as rich text in the PDF itself.
Any idea what I am doing wrong ?
Here is a snnipest of my code:
FileStream stream = File.Open(targetFile, FileMode.Create);
var pdfStamper = new PdfStamper(new PdfReader(sourceFile), stream);
// Iterate the fields in the PDF
foreach (var fieldName in pdfStamper.AcroFields.Fields.Keys)
{
// Get the field value of the current field
var fieldValue = "<?xml version=\"1.0\"?><body xmlns=\"http://www.w3.org/1999/xtml\" xmlns:xfa=\"http://www.xfa.org/schema/xfa-data/1.0/\" xfa:contentType=\"text/html\" xfa:APIVersion=\"Acrobat:8.0.0\" xfa:spec=\"2.4\"><p style=\"text-align:left\"><b><i>Here is some bold italic text</i></b></p><p style= \"font-size:16pt\">This text uses default text state parameters but changes the font size to 16.</p></body>"
// Set the field value
if (String.IsNullOrEmpty(fieldValue) == false)
{
pdfStamper.AcroFields.SetFieldRichValue(key, fieldValue);
}
}
Edit:
I have revised my code based on Mark Storer's post to a question (http://stackoverflow.com/questions/1454701/adding-rich-text-to-an-acrofield-in-itextsharp). The new code is:
// Create reader to read the source file
var reader = new PdfReader(sourceFile);
// Create a stream for the generated file
var stream = File.Open(targetFile, FileMode.Create);
// Create stamper to generate the new file
var pdfStamper = new PdfStamper(reader, stream);
// Field name and value
var fieldName = "myfield";
var fieldValue = "<?xml version=\"1.0\"?><body xfa:APIVersion=\"Acroform:2.7.0.0\" xfa:spec=\"2.1\" xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:xfa=\"http://www.xfa.org/schema/xfa-data/1.0/\"><p dir=\"ltr\" style=\"margin-top:0pt;margin-bottom:0pt;font-family:Helvetica;font-size:12pt\"><b>write line1 bold</b></p</body>";
// Output stream for the temporary file that should contain the apearance of the field
var msOutput = new FileStream(#"d:\temp.pdf", FileMode.Create);
// string reader to read the field value
var textReader = new StringReader(fieldValue);
// Create new document
var document = new Document(pdfStamper.AcroFields.GetFieldPositions(fieldName)[0].position);
// writer for the new doucment
var writer = PdfWriter.GetInstance(document, msOutput);
// Open the document
document.Open();
// Get elements to append to the doucment
var list = HTMLWorker.ParseToList(textReader, null);
// Append elements to the doucment
foreach (var element in list)
{
document.Add(element);
}
// close the documnet
document.Close();
// Append push button that contains the generated content as its apearance
// this approach is based on the suggestion from Mark storer that can be found in:
// http://stackoverflow.com/questions/1454701/adding-rich-text-to-an-acrofield-in-itextsharp
var button = new PushbuttonField(pdfStamper.Writer, pdfStamper.AcroFields.GetFieldPositions(fieldName)[0].position, fieldName + "_")
{
Layout = PushbuttonField.LAYOUT_ICON_ONLY,
BackgroundColor = null,
Template = pdfStamper.Writer.GetImportedPage(new PdfReader(targetFile, 1)
};
pdfStamper.AddAnnotation(button.Field, 1);
pdfStamper.FormFlattening = true;
pdfStamper.Close();
pdfStamper.Dispose();
But the problem now is that the temporary document contains no content....
Any ideas ?
There's a lot of code above, almost 400 lines. In the future, try to distill everything down to a very simple and reproducible test case.
When using SetFieldRichValue you also need to set the PdfStamper's AcroFields.GenerateAppearances property to false:
stamper.AcroFields.GenerateAppearances = false;
You can read more about this here along with some caveats and other workarounds.
I managed to resolve it with little trick - I used Anchor (hyperling) element inside ColumnText element and position it above the form field. The anchor is displayed with underline by default. In order to avoid the hand marker when the user hover the mouse on the anchor, I set the "Reference" property of the anchor to null.
Here is the code I used:
// Create reader
var reader = new PdfReader(sourceFilePathAndName);
// Create stream for the target file
var stream = File.Open(targetFilePathAndName, FileMode.Create);
// Create the stamper
var pdfStamper = new PdfStamper(reader, stream);
const string fieldName = "MyField";
// Get the position of the field
var targetPosition = pdfStamper.AcroFields.GetFieldPositions(fieldName)[0].position;
// Set the font
var fontNormal = FontFactory.GetFont("Arial", 16, Font.UNDERLINE, BaseColor.BLACK);
// Create the anchor
var url = new Anchor("some default text", fontNormal) { Reference = null };
// Create the element that will contain the anchor and allow to position it anywhere on the document
var data = new ColumnText(pdfStamper.GetOverContent(1));
// Add the anchor to its container
data.SetSimpleColumn(url, targetPosition.Left, targetPosition.Bottom, targetPosition.Right, targetPosition.Top, 0, 0);
// Write the content to the document
data.Go();
pdfStamper.FormFlattening = true;
pdfStamper.Close();
pdfStamper.Dispose();

Categories

Resources