C# serialization UIElementCollection - c#

I have some code:
public static UIElementCollection DeSerializeXAML(string filename)
{
// Load XAML from file. Use 'using' so objects are disposed of properly.
using (System.IO.FileStream fs = System.IO.File.Open(filename, System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
return System.Windows.Markup.XamlReader.Load(fs) as UIElementCollection; //EXCEPTION
}
}
// Serializes any UIElement object to XAML using a given filename.
public static void SerializeToXAML(UIElementCollection elements, string filename)
{
// Use XamlWriter object to serialize element
string strXAML = System.Windows.Markup.XamlWriter.Save(elements);
// Write XAML to file. Use 'using' so objects are disposed of properly.
using (System.IO.FileStream fs = System.IO.File.Create(filename))
{
using (System.IO.StreamWriter streamwriter = new System.IO.StreamWriter(fs))
{
streamwriter.Write(strXAML);
}
}
}
private void btnSave_Click(object sender, RoutedEventArgs e)
{
SaveFileDialog dlg = new SaveFileDialog();
dlg.FileName = "UIElement File"; // Default file name
dlg.DefaultExt = ".xaml"; // Default file extension
dlg.Filter = "Xaml File (.xaml)|*.xaml"; // Filter files by extension
// Show save file dialog box
Nullable<bool> result = dlg.ShowDialog();
// Process save file dialog box results
if (result == true)
{
// Save document
string filename = dlg.FileName;
SerializeToXAML(myCanvas.Children, filename);
}
}
private void btnLoad_Click(object sender, RoutedEventArgs e)
{
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
dlg.DefaultExt = ".xaml"; // Default file extension
dlg.Filter = "Xaml File (.xaml)|*.xaml"; // Filter files by extension
// Show open file dialog box
Nullable<bool> result = dlg.ShowDialog();
// Process open file dialog box results
if (result == true)
{
string filename = dlg.FileName;
UIElementCollection elements = DeSerializeXAML(filename) as UIElementCollection;
// Add all child elements (lines, rectangles etc) to canvas
myCanvas.Children.Clear();
foreach (UIElement el in elements)
{
myCanvas.Children.Add(el);
}
}
}
That works fine with serialization but when you deserialize, an exception is thrown.
Text of exception(translated with google):"You did not find a suitable constructor for the type" System.Windows.Controls.UIElementCollection.
"You can use the Arguments or FactoryMethod directives to generate this type.": Line number "1" and position in line "22".

A UIElementCollection instance is tied to a specific Visual, and as such, it is unsuitable for serialization (as #kostya-k points out). The deserialization logic doesn't know how to create a new UIElementCollection because it doesn't know which Visual to associate it with. And creating a new collection is pointless anyway, as you are simply transferring the values to myCanvas.Children.
The good news is that you can use a XamlObjectWriter to populate myCanvas.Children directly instead of instantiatating a new collection:
public static void DeSerializeXAML(UIElementCollection elements, string filename)
{
var context = System.Windows.Markup.XamlReader.GetWpfSchemaContext();
var settings = new System.Xaml.XamlObjectWriterSettings
{
RootObjectInstance = elements
};
using (var reader = new System.Xaml.XamlXmlReader(filename))
using (var writer = new System.Xaml.XamlObjectWriter(context, settings))
{
System.Xaml.XamlServices.Transform(reader, writer);
}
}
private void btnLoad_Click(object sender, RoutedEventArgs e)
{
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
dlg.DefaultExt = ".xaml"; // Default file extension
dlg.Filter = "Xaml File (.xaml)|*.xaml"; // Filter files by extension
// Show open file dialog box
Nullable<bool> result = dlg.ShowDialog();
// Process open file dialog box results
if (result == true)
{
string filename = dlg.FileName;
myCanvas.Children.Clear();
DeSerializeXAML(myCanvas.Children, filename);
}
}

UIElementCollection is not intended for serialization. It meant to be used when building a WPF visual tree.

Related

C# Prompt to warn user of overwriting .txt file

Not sure how to implement this, i am not using SaveFileDialog which i have seen uses OverWritePrompt = true cant seem to get that to work for me.
I am using WPF.
The structure:-
I have a textBox called filePathBox - This contains a file path used from opening an: OpenFileDialog
private void fileBrowser_Click(object sender, RoutedEventArgs e)
{
//Firstly creating the OpenFileDialog
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
//Setting the filter for the file extension of the files as well as the default extension
dlg.DefaultExt = ".txt";
dlg.Filter = "All Files|*.*";
//Display the dialog box by calling the ShowDialog method
Nullable<bool> result = dlg.ShowDialog();
//Grab the file you selected and display it in filePathBox
if (result == true)
{
//Open The document
string filename = dlg.FileName;
filePathBox.Text = filename;
}
}
You can then click a button and the .txt file displays in a textBox called textResult
private void helpfulNotes_Click(object sender, RoutedEventArgs e)
{
if (File.Exists(filePathBox.Text) && System.IO.Path.GetExtension(filePathBox.Text).ToLower() == ".txt")
{
textResult.Text = File.ReadAllText(filePathBox.Text);
}
if (string.IsNullOrWhiteSpace(filePathBox.Text))
{
MessageBox.Show("Please choose a file by clicking on the folder Icon :(");
}
}
Once you have made changes to that text in 'textResult' i have a button to save the text back to the file path that was originally loaded using the OpenFileDialog
private void saveText_Click(object sender, RoutedEventArgs e)
{
if (string.IsNullOrEmpty(textResult.Text))
{
saveText.IsEnabled = false;
MessageBox.Show("No Text to save!");
}
else
{
saveText.IsEnabled = true;
string test = textResult.Text;
System.IO.File.WriteAllText(filePathBox.Text, test);
}
//fileSaveIcon.Visibility = Visibility.Visible;
//fileChangedIcon.Visibility = Visibility.Hidden;
}
At the moment it all saves fine, only it doesn't prompt the user saying are you sure you want to overwrite the file.
At the moment i could
load a file for the purpose of this named TestNote.txt into the
filePathBox
Type some text in textResult before even clicking to display the
file
Click save and it would just overwrite TestNote.txt with the text i
just entered without even warning me
Hopefully i have explained this adequately and provided all the code you need
Just add a messagebox to show your alert message before writing to the text file.
private void saveText_Click(object sender, RoutedEventArgs e)
{
if (string.IsNullOrEmpty(textResult.Text))
{
saveText.IsEnabled = false;
MessageBox.Show("No Text to save!");
}
else
{
if(MessageBox.Show("are you sure you want to overwrite the file.", "Alert", MessageBoxButtons.YesNo)==DialogResult.Yes)
{
saveText.IsEnabled = true;
string test = textResult.Text;
System.IO.File.WriteAllText(filePathBox.Text, test);
}
}
//fileSaveIcon.Visibility = Visibility.Visible;
//fileChangedIcon.Visibility = Visibility.Hidden;
}
Well, OverWritePrompt is a SaveFileDialog property, which you're not using: you're always using File.WriteAllText(), which always overwrites the target file.
You want to provide a Save function that saves an earlier opened file without prompt, a Save As function that prompts the user for a new filename and also call Save As when saving a new file.
This is implemented like this, pseudo:
private string _currentlyOpenedFile;
public void FileOpen_Click(...)
{
var openFileDialog = new ...OpenFileDialog();
if (openFileDialog.ShowDialog())
{
// Save the filename when opening a file.
_currentlyOpenedFile = openFileDialog.FileName;
}
}
public void FileNew_Click(...)
{
// Clear the filename when closing a file or making a new file.
_currentlyOpenedFile = null;
}
public void FileSave_Click(...)
{
if (_currentlyOpenedFile == null)
{
// New file, treat as SaveAs
FileSaveAs_Click();
return;
}
}
public void FileSaveAs_Click(...)
{
var saveFileDialog = new ...SaveFileDialog();
if (openFileDialog.ShowDialog())
{
// Write the file.
File.WriteAllText(text, openFileDialog.FileName);
// Save the filename after writing the file.
_currentlyOpenedFile = openFileDialog.FileName;
}
}
Here you'll be leveraging the SaveFileDialog's functionality which prompts the user whether they want to overwrite an already existing file.

Open image location from textbox

I have openfiledialog that reading user image address with file info and load it in textbox
I want to have another button in order to open image address (that already saved in textbox)
how to code this button at wpf ? I know i should use process.start but no idea !
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
tbl_Moshtari tt = new tbl_Moshtari();
dlg.FileName = "pic-file-name"; // Default file name
dlg.DefaultExt = ".jpg"; // Default file extension
dlg.Filter = "JPEG(.jpeg)|*.jpeg | PNG(.png)|*.png | JPG Files (*.jpg)|*.jpg|GIF Files (*.gif)|*.gif"; // Filter files by extension
Nullable<bool> result = dlg.ShowDialog();
if (result == true)
{
//// picbox.Source = new BitmapImage(new Uri(dlg.FileName, UriKind.Absolute));
//bitmapImage = new BitmapImage();
//bitmapImage.BeginInit();
//bitmapImage.StreamSource = System.IO.File.OpenRead(dlg.FileName);
//bitmapImage.EndInit();
////now, the Position of the StreamSource is not in the begin of the stream.
//picbox.Source = bitmapImage;
FileInfo fi = new FileInfo(dlg.FileName);
string filename = dlg.FileName;
txt_picaddress.Text = filename;
System.Windows.MessageBox.Show("Successfully done");
}
This second button i have
private void btn_go_Click(object sender, RoutedEventArgs e)
{
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
//FileInfo fi = new FileInfo(dlg.FileName);
string filename = dlg.FileName;
Process.Start(filename);
}
This isnt working for me .
Process.Start() should open up the image as long as filename is an absolute path to the file. With that being said, where in your btn_go_Click method are you actually opening up the dialog to get the file name? dlg.FileName returns an empty string if you don't show the dialog in which case Process.Start() fails.
If the file name needs to come from the previous dialog, you shouldn't create a new dialog; instead, change
Process.Start(filename)
to
Process.Start(txt_picaddress.Text)
Of course, you need to do some input verification to make sure the path is correct (unless the textbox is read-only).
Also, consider setting a breakpoint on string filename = dlg.FileName; to make sure it has the correct path to the file if it's still not working.
To open and highlight the file in Windows Explorer:
string filename = txt_picaddress.Text;
ProcessStartInfo pInfo =
new ProcessStartInfo("explorer.exe", string.Format("/Select, {0}", filename));
Process.Start(pInfo);
In your second code sample, you created a new instance of openFileDialog, you need instead to use the previous instance of the openFileDialog that is holding the correct image filename:
if you create the first openFileDialog in the window constructor you can do this:
private void btn_go_Click(object sender, RoutedEventArgs e)
{
string filename = this.dlg.FileName;
Process.Start(filename);
}
hope this helps, this is what i can say given the code you provided.
You don't need an OpenFileDialog in btn_go_Click if you want to use the path in your textbox:
private void btn_go_Click(object sender, RoutedEventArgs e)
{
string filename = txt_picaddress.Text;
Process.Start(filename);
}

Why doesn't my OpenFileDialog work?

I am trying to save and open a file which consists of a list of objects. My problem right now is that when I open the file I saved nothing happens. The program is supposed to use a dragTo event. When I use that event the object that is dragged gets saved in the list "ojl"
Here is my methods for Save and open.
DragTo dragto1 = new DragTo();
OpenFileDialog openDialog = new OpenFileDialog();
SaveFileDialog saveDialog = new SaveFileDialog();
BinaryFormatter form = new BinaryFormatter();
public void Save() // Method to save list of objects (Save)
{
saveDialog.Filter = "dat files (*.dat)|*.dat|All files (*.*)|*.*";
if (saveDialog.ShowDialog() == DialogResult.OK)
{
FileStream outStr = new FileStream(saveDialog.FileName, FileMode.Create); //Create new FileStream
form.Serialize(outStr, dragto1.Ojl);
outStr.Close();
}
}
public void Open() // Method for open saved list of objects (Load/Open)
{
openDialog.Filter = "dat files (*.dat)|*.dat|All files (*.*)|*.*";
if (openDialog.ShowDialog() == DialogResult.OK)
{
FileStream inStr = new FileStream(openDialog.FileName, FileMode.Open); //Create new FileStream
dragto1.Ojl = (List<DrawnObject>)form.Deserialize(inStr);
inStr.Close();
}
and the list is in another class (DragTo)
private List<DrawnObject> ojl = new List<DrawnObject>();
public List<DrawnObject> Ojl
{
get { return ojl; }
set { ojl = value; }
}
I also refresh the controller which the objects are inside of. but the list hasn't got the new values in it from the open method. Does the format of the file have anything to do with it (.dat)?

Save window of controls with runtime geneated controls and reload with as previous state

I created project with thee control buttons. AddButton creates runtime button controls and adds it in canvas1. When i right click on runtime generated controls new window pop ups. I want to save this window and reload it with same state as i leave. I use xml serialisation, it loads but click on that buttons does't work.
Here is my code:
private void AddButton_Click(object sender, RoutedEventArgs e)
{
Button b = new Button();
b.MinHeight = 23;
b.MinWidth = 73;
b.SetValue(Canvas.LeftProperty, e.GetPosition(this).X);
b.SetValue(Canvas.TopProperty, e.GetPosition(this).Y);
b.Content = i.ToString();
canvas1.Children.Add(b);
b.MouseRightButtonUp += new MouseButtonEventHandler(NewButton_Click);
}
private void NewButton_Click(object sender, EventArgs e)
{
Button btn = (Button)sender;
ContextMenu pMenu = new ContextMenu();
MenuItem item1 = new MenuItem();
item1.Header = "Properties";
pMenu.Items.Add(item1);
btn.ContextMenu = pMenu;
item1.Click += new RoutedEventHandler(item1_Click);
}
private void item1_Click(object sender, EventArgs e)
{
MenuItem btn = (MenuItem)sender;
ControlProp c = new ControlProp();
c.ShowDialog();
}
private void Save_Click(object sender, RoutedEventArgs e)
{
StringBuilder outstr = new StringBuilder();
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.OmitXmlDeclaration = true;
settings.NewLineOnAttributes = true;
XamlDesignerSerializationManager dsm = new XamlDesignerSerializationManager(XmlWriter.Create(outstr, settings));
dsm.XamlWriterMode = XamlWriterMode.Expression;
XamlWriter.Save(this.canvas1, dsm);
string savedControls = outstr.ToString();
//Show Dialog Box
Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
dlg.FileName = "Document"; // Default file name
dlg.DefaultExt = ".xaml"; // Default file extension
dlg.Filter = "Xaml documents (.xaml)|*.xaml"; // Filter files by extension
// Show save file dialog box
Nullable<bool> result = dlg.ShowDialog();
// Process save file dialog box results
if (result == true)
{
// Save document
string filename = dlg.FileName;
File.WriteAllText(filename, savedControls);
}
}
private void OpenFile_Click(object sender, RoutedEventArgs e)
{
//Open FileDialog
string filename;
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
dlg.FileName = "Document"; // Default file name
dlg.DefaultExt = ".xaml"; // Default file extension
dlg.Filter = "Xaml documents (.xaml)|*.xaml"; // Filter files by extension
// Show save file dialog box
Nullable<bool> result = dlg.ShowDialog();
// Process save file dialog box results
if (result == true)
{
// Save document
filename = dlg.FileName;
//Open Xaml
StreamReader sR = new StreamReader(filename);
string text = sR.ReadToEnd();
sR.Close();
StringReader stringReader = new StringReader(text);
XmlReader xmlReader = XmlReader.Create(stringReader);
Canvas wp = (Canvas)System.Windows.Markup.XamlReader.Load(xmlReader);
canvas1.Children.Clear(); // clear the existing children
foreach (FrameworkElement child in wp.Children) // and for each child in the WrapPanel we just loaded (wp)
{
canvas1.Children.Add(CloneFrameworkElement(child)); // clone the child and add it to our existing wrap panel
}
}
}
FrameworkElement CloneFrameworkElement(FrameworkElement originalElement)
{
string elementString = XamlWriter.Save(originalElement);
StringReader stringReader = new StringReader(elementString);
XmlReader xmlReader = XmlReader.Create(stringReader);
FrameworkElement clonedElement = (FrameworkElement)XamlReader.Load(xmlReader);
return clonedElement;
}
In short ,i want to save my project that user created at runtime and reopen it like mspaint with save project and open project facility.
You can use XamlWriter (MSDN)

empty path name not legal

I have a "save" button so when users click, it will do a saving of xml file(xml serialization). A savefiledialog is used here and when i press cancel without selecting any file an "Argument Exception" occurs and says "Empty path name is not legal". How do i handle this exception? I would like the form to remain the same even without any path selected in the savefiledialog. Many thanks.
My savefiledialog snippet:
private void SaveButton_Click(object sender, RoutedEventArgs e)
{
string savepath;
SaveFileDialog DialogSave = new SaveFileDialog();
// Default file extension
DialogSave.DefaultExt = "txt";
// Available file extensions
DialogSave.Filter = "XML file (*.xml)|*.xml|All files (*.*)|*.*";
// Adds a extension if the user does not
DialogSave.AddExtension = true;
// Restores the selected directory, next time
DialogSave.RestoreDirectory = true;
// Dialog title
DialogSave.Title = "Where do you want to save the file?";
// Startup directory
DialogSave.InitialDirectory = #"C:/";
DialogSave.ShowDialog();
savepath = DialogSave.FileName;
DialogSave.Dispose();
DialogSave = null;
...
using (Stream savestream = new FileStream(savepath, FileMode.Create))
{
XmlSerializer serializer = new XmlSerializer(typeof(FormSaving));
serializer.Serialize(savestream, formsaving);
}
}
My argument exception occurs at this line:
using (Stream savestream = new FileStream(savepath, FileMode.Create))
{
XmlSerializer serializer = new XmlSerializer(typeof(FormSaving));
serializer.Serialize(savestream, formsaving);
}
The problem here is that you do not care about the result of the Save dialog, and you try to save even if the user clicked Cancel. You should change the code to look something like this instead:
...
DialogSave.InitialDirectory = #"C:/";
if( DialogSave.ShowDialog() == DialogResult.OK )
{
savepath = DialogSave.FileName;
DialogSave = null;
...
using (Stream savestream = new FileStream(savepath, FileMode.Create))
{
XmlSerializer serializer = new XmlSerializer(typeof(FormSaving));
serializer.Serialize(savestream, formsaving);
}
}
DialogSave.Dispose();
You probably don't want to save if the user cancels the dialog? Check for the result from ShowDialog and act accordingly:
if (DialogSave.ShowDialog() == true)
{
savepath = DialogSave.FileName;
...
using (Stream savestream = new FileStream(savepath, FileMode.Create))
{
XmlSerializer serializer = new XmlSerializer(typeof(FormSaving));
serializer.Serialize(savestream, formsaving);
}
}

Categories