xml Parse Exception error when deserializing WPF - c#

I am having problems deserializing a xaml file and get the following error
My code is as follows:
private void SerializeToXML()
{
FileStream filestream = File.Create(#"H:\test1.xaml");
StreamWriter streamwriter = new StreamWriter(filestream);
foreach (ListViewItem Item in slideListView.Items)
{
string mystrXAMLWrite = XamlWriter.Save(Item.Tag);
streamwriter.Write(mystrXAMLWrite);
}
streamwriter.Close();
filestream.Close();
}
private void DeSerialize()
{
FileStream filestream = File.Open(#"H:\test1.xaml", FileMode.Open);
XamlReader reader = new XamlReader();
slideListView = (ListView)reader.LoadAsync(filestream);
}
If I go to the XAML file after saving and change the various names it has problems with, for example changing slideCanvas to slideCanvas1 and ContextMenu to ContextMenu1, then it will load. But obviously this is not a solution and it also means that whatever is loaded back in is not pointing to the correct bits of code as they have had numbers added to the values.
Does anyone know what I need to do here?
UPDATED
Here is the xaml produced when saving one slide object
<Slide imageZIndex="0" editText="False" ClipToBounds="True" xmlns="clr-namespace:StoryboardTool;assembly=StoryboardTool" xmlns:av="http://schemas.microsoft.com/winfx/2006/xaml/presentation"><av:Canvas Background="#FFFFFFFF" Name="slideCanvas" /></Slide>
If I try to place this in a Slide Object for example
Var obj = (Slide)reader.LoadAsync(filestream);
I get this XmalParseExceptionOccured problem.

The error says cannot register duplicate name 'slideCanvas' in this scope. I can only assume that you have another control called 'slideCanvas' that is defined in your application somewhere. Have you tried searching through the entire solution for 'slideCanvas'?
Other than that, there are a few other issues that cause this exception:
Declaring a control in the Resources section using x:Name instead of x:Key.
Trying to serialize a control that has code behind.
You could also try simply removing the names from the controls and binding to them to replicate whatever functionality you named them for.
If you still have a problem, please show the XAML that is causing the error when you try to deserialize it.

How I solved this:
1. Make user control which inherits from your control
2. Add this in the constructor
static int counter = 0;
public TestControl()
{
InitializeComponent();
this.Name += counter.ToString();
counter ++;
}

Related

Read and Save Location of a Form in c sharp

I wanna read the location of a text file so when I reopen my Form it should be at the location I last closed it. Any way to do that?
My code to write into text files:
string path = Directory.GetCurrentDirectory() + #"\config\Loc\dateloc.txt";
if (!File.Exists(path))
{
File.Create(path);
}
try
{
System.IO.File.WriteAllBytes(path, new byte[0]);
StreamWriter writer = new StreamWriter(path, true);
string overlayloc = this.Location.ToString();
writer.WriteLine(overlayloc.ToString());
writer.Dispose();
writer.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
get the value from file in constructor if file exist read the data get x y location and assign to location sorry for not able to understand your question in first glance i hope this works now
public Form1()
{
InitializeComponent();
string path = Environment.CurrentDirectory + #"\config\dateloc.txt";
if (File.Exists(path))
{
string loc = File.ReadAllText(path);
this.Location = new Point(Int32.Parse(loc.Split(',')[0].Replace("{X=", "")), Int32.Parse(loc.Split(',')[1].Replace("Y=", "").Replace("}\r\n","")));
}
}
Given your sample and approach, the answer you were probably initially looking for is provided by #sai kiran.
That is, you're doing ToString() of Form.Location (which is a System.Drawing.Point type) and you're writing that to a file in your approach. Note: the output string of ToString() is (X=?,Y=?), where ? is numerical characters representing the value.
Given that you are storing Location Point value that way (and not the serialized form of Point) and In order to achieve your desire result, you'll need to read that file and parse\handle the string represented value, constructing a new Point type instance from it, then assign it to Location before the form is shown.
There is NO standard Point.Parse method for this ToString string representation of Point (that I'm aware of), so you'll have to handle it with string manipulations and extrapolations. Note: if it was represented as "0, 0", you could deserialize it to Point type instance
Having said that, you can accomplish this task without specifically implementing File\Stream reads\writes nor parsing the extrapolated values of a string by using Application Settings and control Property Binding.
And actually, Using Application Settings and Property Binding is my recommended approach and answer here. I'll provide some instruction on doing that:
You'll define a Setting (for example "Form1LocationPointUserSetting") as a System.Drawing.Point in the scope of User. Since Point is a value type, it will have a default value - (0, 0)
You can define setting in a couple ways, but the easiest is probably using the Settings Designer tool of your IDE (it will generate code and update App.config)
After saving settings designer changes (with CTRL+S to save all), you will be able to both programmatically reference to the Setting property name in code and use it in control property bindings (as it relates to the Type of Property it is). Note: not all control properties support binding in this manner, and some control properties that support bind may not implement\update with INotifyProperty changes.
Lastly, you'll want to persist any changes you've made to settings. So you'll call Property.Settings.Default.Save() during some event. (such as form closing event.)
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
FormClosing += Form1_FormClosing;
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
//Save Settings
Properties.Settings.Default.Save();
}
}
try changing
File.Create(path);
to
File.Create(path).Close();

How do I use strings from XML as variable to create button? C#

To make this easier, I will show my code and then explain what im trying to do.
CODE+EXPLANATION:
First, when the user clicks on a button it goes to Other with additonal information.
private void button1_Click(object sender, EventArgs e)
=> Other("https://pastebin.com/raw/something", "Program1", "A");
private void button2_Click(object sender, EventArgs e)
=> Other("https://pastebin.com/raw/something", "Program2", "B");
Second, I download an XML document and extract neccesary information from it:
private void Other(string UniversalURL, string ProductNAME, string ProductCHANNEL)
{
//Download the Doc
XmlDocument document = new XmlDocument();
document.Load(UniversalURL);
string expandedEnvString = Environment.ExpandEnvironmentVariables("%USERPROFILE%/AppData/Local/Temp/zADU.xml");
File.WriteAllText(expandedEnvString, document.InnerXml);
XmlDocument doc = new XmlDocument();
doc.Load(expandedEnvString);
//Get the needed Nodes
XmlNode nodeXMLProgram = doc.DocumentElement.SelectSingleNode($"/{ProductNAME}");
string XMLProgram = nodeXMLProgram.InnerText;
// Creation of Button Here
}
GOAL: What I want to be able to do is use the strings, extracted from the XML and use them as variables in the creation of button, Kind of like this:
Button Program(XMLProgram) = new Button();
Program(XMLProgram).Height = 22;
Program(XMLProgram).Width = 122;
Program(XMLProgram).BackColor = Color.FromArgb(230, 230, 230);
Program(XMLProgram).ForeColor = Color.Black;
Program(XMLProgram).Name = "DynamicButton";
Program(XMLProgram).Click += new EventHandler(ProgramProgram(XMLProgram)_Click);
Program(XMLProgram).BringToFront();
Controls.Add(ProgramProgram(XMLProgram));
Would I be able to do this? Help would be appreciated! Sorry for confusing title, I don't know how to phrase it properly.
You can use Reflection to look for and set the properties of the object you are deserializing automatically, provided you have a properly formatted XML file.
Read your XML file through XDocument or XmlDocument, extract from it the type of control you need to create (button, textbox, etc), also extract the property names to set from the XML, and the values to set them to. Then create an instance of said control type, and use code like this to go through your property list from the XML and set them in your instance:
// New instance of the control (read the type from the XML and create accordingly)
var ctrlInstance = new Button();
// Get a reference to the type of the control created.
var ctrlType = ctrlInstance.GetType();
// Dictionary to contain property names and values to set (read from XML)
var properties = new Dictionary<string, object>();
foreach (var xmlProp in properties)
{
// Get a reference to the actual property in the type
var prop = ctrlType.GetProperty(xmlProp.Key);
if (prop != null && prop.CanWrite)
{
// If the property is writable set its value on the instance you created
// Note that you have to make sure the value is of the correct type
prop.SetValue(ctrlInstance, xmlProp.Value, null);
}
}
If you intend to create an entire program this way, including code, you will have to use Roslyn to compile your code at runtime, which can be somewhat complicated to put into practice. In that case, you don't need an XML file, you just need to put put all your code into a source file and compile it, then instantiate it in your own program. If you just want to create a form programmatically and handle events in its parent form, this will work fine.

How to modify control properties through variable reference

I've been working on making a project of mine more modular. Something I've wanted to do is have multiple buttons use the same function when they perform a similar action, but with different values. I've been stuck on trying to apply this to the following situation:
"When this button is clicked, have the user select an image, and then have a PictureBox display the selected image". Each button has its own PictureBox. All Controls have been created before runtime.
Hope that makes sense!
My last attempt can be seen in the code below- I have tried assigning the Controls(Button and PictureBox) to variables to be stored together in a class. There's 6 of these classes all included within a single List.
I've also tried to store only the Control Names and then using this.Controls.Find to retrieve the Controls.
I've tried quite a few smaller changes such as passing by reference, making the List static, and things such as that would (somehow)magically do the trick- I've gotten desperate.
public class score_control
{
public Button score_button;
public PictureBox score_picture;
public int picture_index;
}
public List<string> score_boxes_names = new List<string>();
public List<score_control> score_boxes = new List<score_control>();
public void add_score_control(Button button, PictureBox pictureBox)
{
score_control new_score = new score_control();
new_score.score_button = button;
new_score.score_picture = pictureBox;
new_score.picture_index = score_boxes.Count();
score_boxes.Add(new_score);
score_boxes_names.Add(button.Name);
}
public score_control find_score_control(string name)
{
int index = score_boxes_names.IndexOf(name);
return score_boxes[index];
}
public frm_settings()
{
InitializeComponent();
add_score_control(btn_score1_image1, pic_score1_image1);
add_score_control(btn_score1_image2, pic_score1_image2);
add_score_control(btn_score1_image3, pic_score1_image3);
add_score_control(btn_score2_image1, pic_score2_image1);
add_score_control(btn_score2_image2, pic_score2_image2);
add_score_control(btn_score2_image3, pic_score2_image3);
}
private void score_button_Click(object sender, EventArgs e)
{
Button image_button = (Button)sender;
if (ofd_png.ShowDialog() == DialogResult.OK)
{
score_control clicked_control = find_score_control(image_button.Name);
score_image[clicked_control.picture_index] = ofd_png.FileName;
clicked_control.score_picture.Image = Image.FromFile(ofd_png.FileName);
}
}
The problem seems centered around this line:
clicked_control.score_picture.Image = Image.FromFile(ofd_png.FileName);
The program throws a NullReferenceException , but clickedcontrol is being recognized in the Local Watch, as well as score_image being noted to be a PictureBox(as it should be).
When I instead held the Control Names in the class, I had broke this line down into multiple lines, but the following line produced a NullReferenceException:
Control[] find_control = this.Controls.Find(clicked_control.score_picture, true);
In this case, clicked_control.score_picture would be a string containing the PictureBox Name. Again, the Local Watch showed that it clicked_control was not null, and neither was score_picture.
Any help figuring out how to properly store a Control within a variable to later be used to modify that Control's properties would be greatly appreciated.
dontpanic was able to help me out with this one. The issue was actually outside of this code - it had to do with the line score_image[clicked_control.picture_index] = ofd_png.FileName;. The way score_image was initialized as an array was incorrect. Fixing that made everything work fine.

using an array of Settings in C#

i want to write a program that somehow is like a designer where user can add textbox on the form and everything the user put into those textbox can be saved (like a setting) and after closing and opening the form again textboxs' text will remail unchanged.
so i decided to make a setting in project->settings and then make an array of it in my code.
but whenever i want to access my settings it gives me an exception:
"An unhandled exception of type 'System.NullReferenceException' occurred in FormDesigner.exe"
here is my code from defining the array:
Settings[] formsetting=new Settings[3];
and here is my code for handling the textchanged event for everytext box:
(i use the textboxs' tag to match the settings index with every textbox)
void t_TextChanged(object sender, EventArgs e)
{
TextBox temp = (TextBox)sender;
int s =(int) temp.Tag;
string str = temp.Text;
frmsetting[s].text = str;
}
the last line is where i get the error.
could someone explain to me what is the problem and how to fix it?
and if my way is wrong could you please show my another way of doing this.
thanks
You haven't initialized the objects in the array.
Doing this:
Settings[] formsetting = new Settings[3];
..creates the array. All 3 are null though. Do this:
var formsetting = new Settings[3] {
new Settings(),
new Settings(),
new Settings()
};
While you are initializing your array, you are not actually initializing any of the values. What you have currently is equivalent to the following:
Settings[] formsetting=new Settings[3];
formsetting[0] = null;
formsetting[1] = null;
formsetting[2] = null;
You need to initialize the value at the index you want to use before doing anything with it.

How to pass string parameter of a method from one class to another class in same namespace?

Little silly question, but got stuck for a long time.
I have written two classes one which is a Form (TreeDisplay class) and other which contains buiseness logic (MyTreeNode class).
TreeDisplay class contains browse button to select a file pass it to a method initiatingTree(string filename) which is in MyTreeNode class.
Now I have to pass this string parameter filename to MyTreeNode class. When I run my code the XML file which I have selected is shown in the textbox but not in treeview.
I have written the part of code but it is throwing NullReferenceException(Object reference not set to an instance of an object).
When the whole code was writeen in Form.cs the code was running successfully but on separating the business logic the exception has occured.
Can you please tell me where I am wrong?
This is the code in Browse button of TreeDisplay class (My main form):
if (open.ShowDialog(this) == DialogResult.OK)
{
txtFileName.Text = open.FileName;
MytreeNodeClass treenodeClass = new MytreeNodeClass();
treenodeClass.initiatingTree(open.FileName,treeView1);
}
Here is the code of initiatingTree() in my MyTreeNode class:
public class MytreeNodeClass
{
private readonly System.Windows.Forms.TextBox txtFileName;
private TreeView treeView1;
private readonly ToolStripStatusLabel toolStripStatusLabel1;
public string Filename
{
get { return filename; }
}
protected string filename;
public MytreeNodeClass()
{
}
public void initiatingTree(string nameofFile,TreeView treeView1)
{
try
{
//Create XML document & load the XML file.
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(nameofFile);
treeView1 = new System.Windows.Forms.TreeView();
treeView1.Nodes.Clear();
if (xmlDocument.DocumentElement != null)
{
TreeNode treeNodedoc = new TreeNode(xmlDocument.DocumentElement.Name);
treeView1.Nodes.Add(treeNodedoc);
}
On using breakpoint treeView1.Nodes.Clear(), the code comes out from this line and enters the catch block throwing NullReferenceException.
Please help to find root cause of exception. Thanks.
What is the value of treeView1 at your breakpoint?
I suggest this may be null, as the reference isn't available in your Business Logic Layer.
Updated with sample code:
public void initiatingTree(string nameofFile, TreeView treeView1)
{
try
{
//Create XML document & load the XML file.
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(nameofFile);
treeView1.Nodes.Clear();
if (xmlDocument.DocumentElement != null)
{
TreeNode treeNodedoc = new TreeNode(xmlDocument.DocumentElement.Name);
treeView1.Nodes.Add(treeNodedoc);
}
}
}
and where you call this:
if (open.ShowDialog(this) == DialogResult.OK)
{
txtFileName.Text = open.FileName;
MytreeNodeClass treenodeClass = new MytreeNodeClass();
treenodeClass.initiatingTree(open.FileName, treeView1);
}
As c.k said.
You don't have access to the usercontrols from your business layer as a standard.
May i suggest that you keep you control code in the gui code behind for simplicity.
An example how to sort your code
(Gui Layer) Codebehind for control interaction
Business Layer for data manipulation
Data Layer for database manipulations and such
Initialize the treeView1 object before accessing it.
I guess you copied and pasted, right?
Anyways here's a little note:
When you drag controls on a form in VS Designer, vs generates code for these controls "usually in InitializeComponent()". VS writes the references in your class (e.g form1.cs) like the following:
private System.Windows.Forms.TreeView treeView1;
this is just declaring a variable of type System.Windows.Forms.TreeView this variable (itself) is stored on the stack, because it's just a reference, a reference that doesn't point to any actual heap objects till now (i.e NullReference). Now this reference is useless and you can't use it unless you initialize it and tell it to point to a real object on the heap, and that's what VS does for you in the designer, it simply adds the next line to InitializComponents:
this.treeView1 = new System.Windows.Forms.TreeView();
And this is the line that you forgot to copy to the other class, which left your reference uninitialized (i.e still NullReference), hence when you tried to use it, a NullReferenceException was thrown. I guess this is your problem or at least this is how i could understand it. Forgive me if i failed to understand you!

Categories