Deserialize Object in a different Assembly - Binary Formatter - c#

Background:
I got the Source-Code of a Tool, that is used for many years. It has a Class (DB_Para), which get serialized by BinaryFormatter. Hundredes of File got created that way - So changing the the "saving"-process is not possible.
My Goal is, to import these Files into my Software.
My Attempt was to copy the class to my SW, but when I try to open the File i get this Error:
System.Runtime.Serialization.SerializationException: "Die Assembly "FTF-Para, Version=1.16.0.0, Culture=neutral, PublicKeyToken=null" could not be found."
What would be the best way to approach this?
OLD Assembly Saving:
private void Save(object sender, RoutedEventArgs e)
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.DefaultExt = "*.fpb";
sfd.Filter = "FTF-Para-Datei (*.fpb) |*.fpb";
sfd.Title = "Speichern unter";
bool? res = sfd.ShowDialog();
if (res == true)
{
BinaryFormatter formatter = new BinaryFormatter();
FileStream stream = new FileStream(sfd.FileName, FileMode.Create);
formatter.Serialize(stream, this.DataContext);
stream.Close();
}
}
OLD Assembly Class:
[Serializable()]
public class DB_Para : INotifyPropertyChanged
{
[field: NonSerialized]
public event PropertyChangedEventHandler PropertyChanged;
private int _Rack, _Slot;
public int Rack
{
get { return _Rack; }
set { _Rack = value; }
}
public int Slot
{
get { return _Slot; }
set { _Slot = value; }
}
//Many more Attributes ...
}

Related

How to load an image and access it from everywhere?

I would like to browse an image from form window. Also I created a class and created some filters. I can read this image from form.
My goal is declare it in my class. And use this image in everywhere. But I don't know how can I do this.
private void btn_BROWSE_Click(object sender, EventArgs e)
{
OpenFileDialog imge = new OpenFileDialog();
imge.Filter = "Extensions |*.bmp;*.jpg;*.jpeg;*.png;*.tif;*.tiff|"
+ "BMP|*.bmp|GIF|*.gif|JPG|*.jpg;*.jpeg|PNG|*.png|TIFF|*.tif;*.tiff|"
+ "Zip Files|*.zip;*.rar";
imge.ShowDialog();
string imgepath = imge.FileName;
pBox_SOURCE.ImageLocation = imgepath;//i'm browsing an image
}
private void sliderKernel_MouseUp(object sender, MouseEventArgs e)
{
Bitmap OriginalImage = new Bitmap(pBox_SOURCE.Image);
}
class Filters
{
// (i would like to initialize my image in here not in form :) )
}
I would define an abstract class Filter and implement every filter as an heir of that class.
public abstract class Filter
{
public Bitmap Image { get; set; }
public abstract void Apply();
}
An implementation would be:
public class SliderKernel : Filter
{
public overrides void Apply()
{
//manipulates the Image property
}
}
If you want to use that image everywhere you should declare it as a static member of a class:
public static class ImageContainer
{
public static Bitmap Image { get; set; }
}
You can use all this in your form code like this:
private void btn_BROWSE_Click(object sender, EventArgs e)
{
OpenFileDialog imge = new OpenFileDialog();
imge.Filter = "Extensions |*.bmp;*.jpg;*.jpeg;*.png;*.tif;*.tiff|"
+ "BMP|*.bmp|GIF|*.gif|JPG|*.jpg;*.jpeg|PNG|*.png|TIFF|*.tif;*.tiff|"
+ "Zip Files|*.zip;*.rar";
imge.ShowDialog();
string imgepath = imge.FileName;
pBox_SOURCE.ImageLocation = imgepath;//i'm browsing an image
//save the image to the container
ImageContainer.Image = new Bitmap(pBox_SOURCE.Image);
}
private void sliderKernel_MouseUp(object sender, MouseEventArgs e)
{
Filter filter = new SliderKernel () { Image = ImageContainer.Image };
filter.Apply();
}
I think you should turn the image into a byte array
using the following code and store it in a static class
public byte[] ImageToByteArray(System.Drawing.Image imageIn)
{
using (var ms = new MemoryStream())
{
imageIn.Save(ms,imageIn.RawFormat);
return ms.ToArray();
}
}
https://www.codeproject.com/Articles/15460/C-Image-to-Byte-Array-and-Byte-Array-to-Image-Conv
And use this code to turn into a graphic to display in pictureBox
public Image byteArrayToImage(byte[] byteArrayIn)
{
MemoryStream ms = new MemoryStream(byteArrayIn);
Image returnImage = Image.FromStream(ms);
return returnImage;
}

Image edit and save Out of Memory Exception C#

I'm working in a WPF application where I show my images in two places which means the same image gets loaded in two places. In one of the place the image will be shown along with other few images in a slider where it will be able to edit and save. If there is no image available in the location I should be showing a separate image Image not found which is not editable.
When I started working on the functionality I got the Used by another process exception during edit and save. So after searching I came up with a solution and now at a rare time I get the Out of memory exception when I click the Next or Previous or First or Last in slider. The slider is just an Image control with 4 buttons. When the buttons are clicked the below method is called. I'm not sure if there is any memory leaks.
bool NoImage = true;
private static readonly object _syncRoot = new object();
private BitmapSource LoadImage(string path)
{
lock (_syncRoot) //lock the object so it doesn't get executed more than once at a time.
{
BitmapDecoder decoder = null;
try
{
//If the image is not found in the folder, then show the image not found.
if (!File.Exists(path) && (path != null))
{
System.Drawing.Bitmap ss = XXXX.Resources.ImageNotFound;
var stream = new System.IO.MemoryStream();
if (!File.Exists(Path.GetTempPath() + "ImageNotFound.jpg"))
{
FileStream file = new FileStream(Path.GetTempPath() + "ImageNotFound.jpg", FileMode.Create, FileAccess.Write);
ss.Save(stream, ImageFormat.Jpeg);
stream.Position = 0;
stream.WriteTo(file);
file.Close();
stream.Close();
}
path = Path.Combine(Path.GetTempPath(), "ImageNotFound.jpg");
NoImage = false;
}
else
{
if (!EnableForEdit)
NoImage = false;
else
NoImage = true;
}
if (!string.IsNullOrEmpty(path) && (!NoImage || File.Exists(path)))
{
using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read))
{
decoder = BitmapDecoder.Create(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}
return decoder.Frames.FirstOrDefault();
}
else
return null;
}
catch (OutOfMemoryException ex)
{
MessageBox.Show("Insufficient memory to handle the process. Please try again later.", "Application alert");
return null;
}
catch (Exception ex)
{
// Error handling.
throw new ApplicationException(ex.Message);
}
finally
{
decoder = null;
GC.WaitForFullGCComplete(1000);
GC.Collect(0, GCCollectionMode.Forced);
}
}
}
<Image x:Name="viewImage" Grid.Row="2" Height="100" Width="135" Source="{Binding DisplayImage, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True}" />
If my approach is wrong, let me know where should I do the change or if there is any simpler way to do. Kindly help.
Note: The images which are loaded is above 5Mb
Firstly when ever you create a stream you need to dispose of it once you are finished with it (Note Close does not Dispose, but Dispose does close), if not then the stream stays in memory consuming resources
so your code should look as follows
using(var stream = new System.IO.MemoryStream())
{
if (!File.Exists(Path.GetTempPath() + "ImageNotFound.jpg"))
{
using(FileStream file = new FileStream(Path.GetTempPath() + "ImageNotFound.jpg", FileMode.Create, FileAccess.Write))
{
ss.Save(stream, ImageFormat.Jpeg);
stream.Position = 0;
stream.WriteTo(file);
}
}
}
Second you need to reduce your apps memory impact
to do that i would suggest leveraging the functionality already in WPF here is a quick example of how you should do this
Your Model
public class ImageItem
{
public Uri URI{ get; set; }
private BitmapSource _Source;
public BitmapSource Source
{
get
{
try
{
if (_Source == null) _Source = new BitmapImage(URI);//lazy loading
}
catch (Exception)
{
_Source = null;
}
return _Source;
}
}
public void Save(string filename)
{
var img = BitmapFrame.Create(Source);
var encoder = new JpegBitmapEncoder();
encoder.Frames.Add(img);
using(var saveStream = System.IO.File.OpenWrite(filename))
encoder.Save(saveStream)
}
}
Your View Model
public class ImageList : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public ObservableCollection<ImageItem> Images { get; } = new ObservableCollection<ImageItem>();
private int _SelectedIndex;
// c# >= 6
public static readonly PropertyChangedEventArgs SelectedIndexProperty = new PropertyChangedEventArgs(nameof(SelectedIndex));
// c# < 6
// public static readonly PropertyChangedEventArgs SelectedIndexProperty = new PropertyChangedEventArgs("SelectedIndex");
public int SelectedIndex
{
get { return _SelectedIndex; }
set
{
_SelectedIndex = value;
// c# >= 6
PropertyChanged?.Invoke(this, SelectedIndexProperty);
PropertyChanged?.Invoke(this, CurrentImageProperty);
// c# < 6
// var handler = PropertyChanged;
// if(handler !=null)
// {
// handler (this, SelectedIndexProperty);
// handler (this, CurrentImageProperty);
// }
}
}
// c# >= 6
public static readonly PropertyChangedEventArgs CurrentImageProperty = new PropertyChangedEventArgs(nameof(CurrentImage));
// c# < 6
// public static readonly PropertyChangedEventArgs CurrentImageProperty = new PropertyChangedEventArgs("CurrentImage");
public ImageItem CurrentImage => Images.Count>0 ? Images[SelectedIndex] : null;
public void Next()
{
if (SelectedIndex < Images.Count - 1)
SelectedIndex++;
else
SelectedIndex = 0;
}
public void Back()
{
if (SelectedIndex == 0)
SelectedIndex = Images.Count - 1;
else
SelectedIndex--;
}
public void Add(string Filename)
{
Images.Add(new ImageItem() { URI= new Uri(Filename) });
// c# >= 6
PropertyChanged?.Invoke(this, CurrentImageProperty);
// c# < 6
// var handler = PropertyChanged;
// if(handler !=null)
// {
// handler (this, CurrentImageProperty);
// }
}
}
and Finally your View
<Window x:Class="ImageDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ImageDemo"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<BitmapImage x:Key="NotFound" UriSource="C:\...\NotFound.png"/>
</Window.Resources>
<Window.DataContext>
<local:ImageList/>
</Window.DataContext>
<DockPanel>
<Button Content="<" Click="Back_Click"/>
<Button DockPanel.Dock="Right" Content=">" Click="Next_Click"/>
<Image Source="{Binding CurrentImage.Source, Mode=OneWay,
TargetNullValue={StaticResource NotFound},
FallbackValue={StaticResource NotFound}}"/>
</DockPanel>
</Window>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
//c# >= 6
private ImageList list => DataContext as ImageList;
//c# < 6
//private ImageList list {get{ return DataContext as ImageList;}}
private void Next_Click(object sender, RoutedEventArgs e)
{
list.Next();
}
private void Back_Click(object sender, RoutedEventArgs e)
{
list.Back();
}
}
note:
because the Model is separate to the View you can show the same image in several places with no issue at all
also System.Drawing.Bitmap is not WPF compatible so you should use the WPF classes in System.Windows.Media.Imaging

Show text file data in textbox with Data binding

I am trying to read the text file in textbox with the help of data binding.
Here is the code of class where i used get and set properties
public class FileData : INotifyPropertyChanged
{
public string data;
public string Data
{
get { return data; }
set
{
data = value;
OnPropertyChanged();
}
}
public FileData(string data)
{
Data = data;
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string caller = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(caller));
}
}
}
}
And this is the code of Mainpage.Xaml.cs
private async void Button_Click_1(object sender, RoutedEventArgs e)
{
display.DataContext = fd;
StorageFile file = await ApplicationData.Current.LocalFolder.GetFileAsync(filenamebox.Text + ".txt");
fd.Data = await FileIO.ReadTextAsync(file);
}
And when i read the file this exception comes out
"Object reference not set to an instance of an object."
please help me :(
Check if file return is null or not
StorageFile file = await ApplicationData.Current.LocalFolder.GetFileAsync(filenamebox.Text + ".txt");
if ( file != null)
{
// Do what you want
}

How to send a variable from one class to another

Here is the code as it now stands, I will include all of the code of the program as I left some bits out before. The bits I have changed due to your help I have emphasized with asterisks and ///
The first class is the standard one created from Windows Forms when directly editing your form.
namespace DistanceEstimatorFinal
{
public partial class Form1 : Form
{
private bool saved;
public Form1()
{
dataPoints mydataPoints = new dataPoints();
InitializeComponent();
dataPoint a = mydataPoints.getItem(0);
latTextBox.Text = a.CurLatitude;
longTextbox.Text = a.CurLongtitude;
eleTextBox.Text = a.CurElevation;
saved = true;
}
private void latTextBox_TextChanged(object sender, EventArgs e)
{
}
private void openDataListToolStripMenuItem_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "CSV files (*.csv)|*.csv|Text files ( *.txt)|*.txt |All files (*.*)|*.*";
if (ofd.ShowDialog(this).Equals(DialogResult.OK))
{
*var dp = new dataPoints (ofd.FileName);* /////
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (saved)
{
if (MessageBox.Show("Save?", "Data Not Saved", MessageBoxButtons.YesNo).Equals(DialogResult.Yes))
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.ShowDialog();
}
}
}
private void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
{
SaveFileDialog sfd1 = new SaveFileDialog();
sfd1.Filter = "CSV files (*.csv)|*.csv|Text files ( *.txt)|*.txt |All files (*.*)|*.*";
sfd1.ShowDialog();
}
}
}
This class was designed to read in the data from a file, I am currently adapting it to read in a file from the open function.
namespace DistanceEstimatorFinal
{
public class dataPoints
{
List<dataPoint> Points;
string p;
public dataPoints(string path)
{
p = path;
Points = new List<dataPoint>();
StreamReader tr = new StreamReader(p);
string input;
while ((input = tr.ReadLine()) != null)
{
string[] bits = input.Split(',');
dataPoint a = new dataPoint(bits[0],bits[1],bits[2]);
Points.Add(a);
}
tr.Close();
}
internal dataPoint getItem(int p)
{
if (p < Points.Count)
{
return Points[p];
}
else
return null;
}
}
}
This file held the three variables Distance, latitude and Longtitude.
namespace DistanceEstimatorFinal
{
class dataPoint
{
private string latitude;
private string longtitude;
private string elevation;
public dataPoint() //Overloaded incase no value available
{
latitude = "No Latitude Specified";
longtitude = "No Longtitude Specified";
elevation = "No Elevation Specified";
}
public dataPoint(string Latitude, string Longtitude, string Elevation)
{
// TODO: Complete member initialization
this.latitude = Latitude;
this.longtitude = Longtitude;
this.elevation = Elevation;
}
public string CurLongtitude { get { return this.longtitude; } }
public string CurLatitude { get { return this.latitude; } }
public string CurElevation { get { return this.elevation; } }
}
Your pathFile is a method local variable, so it's inacccesible anywhere except the body of that method (here openDataListToolStripMenuItem_Click).
You could add a parameter to your dataPoints constructor to pass that value to the class:
public class dataPoints
{
List<dataPoint> Points;
public dataPoints(string path)
{
Points = new List<dataPoint>();
//here `path` from constructor arguments
TextReader tr = new StreamReader(path);
//...rest part of your code
}
Besides you'll have to pass the value to this constructor. You didn't show the code, you have to create dataPoints instanses.
var dp = new dataPoints(pathFile);
But remember, pathFile is accessible only in openDataListToolStripMenuItem_Click. So you should either create the dataPoints right there, or make your pathFile a field of a form for it to be accessible in any method of that form. Then you'd get an opportunity to access pathFile in any method of this form.
According to your previous post, this should look like:
private void openDataListToolStripMenuItem_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "CSV files (*.csv)|*.csv|Text files ( *.txt)|*.txt |All files (*.*)|*.*";
if (ofd.ShowDialog(this).Equals(DialogResult.OK))
{
//actually you don't even need to have a separate `pathFile` variable
//just pass the value from the dialog straight to your `dataPoints` object
var dp = new dataPoints(ofd.FileName);
//...rest of your code
}
}
P.S.: off-topic, but, please, consider reading MSDN Guidelines for Names

Something wrong with xml serialization/deserialization

I'm dipping my feet into Windows Phone development and are starting to get to terms with some of the features of Silverlight on WP, but I'm struggling with XML:
I'm trying to serialize some objects into an XML and then read the said XML and serialize it into objects again. Then I'll use that to populate a listbox by putting an ObservableCollection as the ItemsSource of the listbox.
I've already made sure that the databinding works properly; if I just generate the objects and put them into an Observable Collection and then put that as the ItemsSource, there are no problems. It would seem that it's the XML part of my code that's faulting. Everything compiles and executes nice enough, but the listbox remains empty :(
This code executes as the app launches (not very effective but works for my testing):
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
ObservableCollection<Quote> quotes = new ObservableCollection<Quote>();
for (int i = 0; i < 10; i++)
{
Quote quote = new Quote()
{
Author = "Author #" + i.ToString(),
QuoteText = "This is quote #" + i.ToString(),
};
quotes.Add(quote);
}
XmlWriterSettings xmlwrtrstngs = new XmlWriterSettings();
xmlwrtrstngs.Indent = true;
using(IsolatedStorageFile isostrg = IsolatedStorageFile.GetUserStoreForApplication())
{
using(IsolatedStorageFileStream isoflstrm = isostrg.OpenFile("Quotes.xml", FileMode.Create))
{
XmlSerializer xmlsrlzr = new XmlSerializer(typeof(QuoteCollection));
using(XmlWriter xmlwrtr = XmlWriter.Create(isoflstrm, xmlwrtrstngs))
{
xmlsrlzr.Serialize(xmlwrtr, quoteCollection);
}
}
}
loadData();
}
void loadData()
{
try
{
using(IsolatedStorageFile isostrg = IsolatedStorageFile.GetUserStoreForApplication())
{
using(IsolatedStorageFileStream isoflstrm = isostrg.OpenFile("Quotes.xml", FileMode.Open))
{
XmlSerializer xmlsrlzr = new XmlSerializer(typeof(QuoteCollection));
QuoteCollection quoteCollectionFromXML = (QuoteCollection)xmlsrlzr.Deserialize(isoflstrm);
LstBx.ItemsSource = quoteCollectionFromXML.Quotes;
}
}
}
catch(Exception)
{
Console.Write("Something went wrong with the XML!");
}
}
QuoteCollection
public class QuoteCollection : INotifyPropertyChanged
{
ObservableCollection<Quote> quotes;
public event PropertyChangedEventHandler PropertyChanged;
public ObservableCollection<Quote> Quotes
{
get { return quotes; }
set
{
if(quotes != value)
{
quotes = value;
raisePropertyChanged("Quotes");
}
}
}
protected virtual void raisePropertyChanged(string argPropertyChanged)
{
if(PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(argPropertyChanged));
}
}
}
Quote
public class Quote : INotifyPropertyChanged
{
string author;
string quoteText;
public event PropertyChangedEventHandler PropertyChanged;
public string Author
{
get
{
return author;
}
set
{
if(author != value)
{
author = value;
onPropertyChanged("Author");
}
}
}
public string QuoteText
{
get
{
return quoteText;
}
set
{
if(quoteText != value)
{
quoteText = value;
onPropertyChanged("QuoteText");
}
}
}
protected virtual void onPropertyChanged(string argProperty)
{
if(PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(argProperty));
}
}
}
Any insight would be most appreciated :)
You are serializing using QuoteCollection as the type, but actually writing out an ObservableCollection<Quote>.
Forgot to put the ObservableCollection into the QuoteCollection instance I'd made previously (not shown in the code posted).

Categories

Resources