I have a Web image with specified URL, it can be browsed in the browser.
i tried to retrieve it from web url and when program goes to bitmapImage.SetSource(ms); i get a exception "
ex = {System.Exception: The component cannot be found. (Exception from HRESULT: 0x88982F50)
at MS.Internal.XcpImports.CheckHResult(UInt32 hr)
at MS.Internal.XcpImports.BitmapSource_SetSource(BitmapSource bitmapSource, CValue& byteStream)
at System.Wi...
"
i did searched other questions on stackoverflow...but no help on this. any one can help me?
byte array did have data, in the runtime debugging, it returns imageByteArray = {byte[1227]}; my option is that exception occurs when converting byte array to BitmapImage.
in the httpclient wrapper class:
public static async Task<Byte[]> GetWebImageByImageName(string ImageName)
{
//Uri imageServerUril = new Uri(ImageName);
var requestMessage = new HttpRequestMessage(HttpMethod.Get, ImageName);
var responseMessage = await client.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead);
var responseData = await responseMessage.Content.ReadAsByteArrayAsync();
return responseData;
}
in the view model:
private async void ReadArticleList(int pageNumber)
{
string webURL = "http://....."; // the web URL is no problem
try
{
byte[] imageByteArray = await CollectionHttpClient.GetWebImageByImageName(webURL);//
//Convert it to BitmapImage
using (MemoryStream ms = new MemoryStream(imageByteArray))
{
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.CreateOptions = BitmapCreateOptions.DelayCreation;
bitmapImage.SetSource(ms); // the exception got here
item.BitImage = bitmapImage;
}
IsLoading = false;
}
catch(Exception ex)
{
if (ex.HResult == -2146233088 && ex.Message.Equals("Response status code does not indicate success: 404 ()."))
{
MessageBox.Show("The network is not set right. Internet cannot be accessed.");
}
else
{
MessageBox.Show("sorry, no data.");
}
IsLoading = false;
}
}
* for Detail *
BitImage is a instance of BitmapImage;
item.BitImage: item is a instance of Article
image format is JPEG
Article model is in below:
public class Article : INotifyPropertyChanged
{
private long _Id;
public long ID
{
get { return _Id; }
set
{
if (_Id != value)
{
_Id = value;
NotifyPropertyChanged("ID");
}
}
}
private string _subject;
public string Subject
{
get
{
return _subject;
}
set
{
if (_subject != value)
{
_subject = value;
NotifyPropertyChanged("Subject");
}
}
}
private string _words;
public string Words
{
get
{
return _words;
}
set
{
if (_words != value)
{
_words = value;
NotifyPropertyChanged("Words");
}
}
}
private DateTime _publishDate;
public DateTime PublishDate
{
get
{ return _publishDate; }
set
{
if (_publishDate != value)
{
_publishDate = value;
NotifyPropertyChanged("PublishDate");
}
}
}
public List<string> ImagePathList = new List<string>();
public BitmapImage BitImage = new BitmapImage();
private string _firstImage;
public string FirstImage
{
get
{
return _firstImage;
}
set
{
if (_firstImage != value)
{
_firstImage = value;
NotifyPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
If you just want to display an image from a remote server without saving it, do the following:
imageControl1.Source = new BitmapImage(new Uri("http://delisle.saskatooncatholic.ca/sites/delisle.saskatooncatholic.ca/files/sample-1.jpg", UriKind.Absolute));
If you want to save the image to IsolatedStorage you can do the following:
WebClient webClientImg = new WebClient();
webClientImg.OpenReadCompleted += new OpenReadCompletedEventHandler(client_OpenReadCompleted);
webClientImg.OpenReadAsync(new Uri("http://delisle.saskatooncatholic.ca/sites/delisle.saskatooncatholic.ca/files/sample-1.jpg", UriKind.Absolute));
void client_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
isSpaceAvailable = IsSpaceIsAvailable(e.Result.Length);
if (isSpaceAvailable)
{
SaveToJpeg(e.Result);
}
else
{
MessageBox.Show("You are running low on storage space on your phone. Hence the image will be loaded from the internet and not saved on the phone.", "Warning", MessageBoxButton.OK);
}
}
Function to check if IsolatedStorage space is available or else it will not download the image.
private bool IsSpaceIsAvailable(long spaceReq)
{
using (var store = IsolatedStorageFile.GetUserStoreForApplication())
{
long spaceAvail = store.AvailableFreeSpace;
if (spaceReq > spaceAvail)
{
return false;
}
return true;
}
}
If space was available, save as image to IsolatedStorage using the below function:
private void SaveToJpeg(Stream stream)
{
using (IsolatedStorageFile iso = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream isostream = iso.CreateFile("image1.jpg"))
{
BitmapImage bitmap = new BitmapImage();
bitmap.SetSource(stream);
WriteableBitmap wb = new WriteableBitmap(bitmap);
// Encode WriteableBitmap object to a JPEG stream.
Extensions.SaveJpeg(wb, isostream, wb.PixelWidth, wb.PixelHeight, 0, 85);
isostream.Close();
LoadImageFromIsolatedStorage(); //Load recently saved image into the image control
}
}
}
Load the image in image control from IsolatedStorage:
private void LoadImageFromIsolatedStorage()
{
byte[] data;
try
{
using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream isfs = isf.OpenFile("image1.jpg", FileMode.Open, FileAccess.Read))
{
data = new byte[isfs.Length];
isfs.Read(data, 0, data.Length);
isfs.Close();
}
}
MemoryStream ms = new MemoryStream(data);
BitmapImage bi = new BitmapImage();
bi.SetSource(ms);
imageControl1.Source = bi;
}
catch
{
}
}
Image taken randomly from Google Search. Credits to the image lie to the owner.
Hope this helps. :)
#Mark , you are correct, this works according to what you suggest.
i think the problem is if i used code below, i got the byte array is byte[1227]
var requestMessage = new HttpRequestMessage(HttpMethod.Get, ImageName);
var responseMessage = await client.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead);
var responseData = await responseMessage.Content.ReadAsByteArrayAsync();
return responseData;
and if i use var byteArray = await client.GetByteArrayAsync(ImageName); the byte array size is byte[5996]
i do not know why this happens, but Mark's solution works.
all my code is as below:
in a MVVM pattern
// get image from URL, ImageName is an absolute Url
public static async Task<BitmapImage> GetWebImageByImageName(string ImageName)
{
//Uri imageServerUril = new Uri(ImageName);
var byteArray = await client.GetByteArrayAsync(ImageName);
//Convert byte array to BitmapImage
BitmapImage bitmapImage;
using (MemoryStream ms = new MemoryStream(byteArray))
{
bitmapImage = new BitmapImage();
bitmapImage.SetSource(ms);
}
return bitmapImage;
}
in the ViewModel
public void LoadPage(int pageNumber)
{
if (pageNumber == 1)
{
this.ArticleCollection.Clear();
}
IsLoading = true;
ReadArticleList(pageNumber);
}
private async void ReadArticleList(int pageNumber)
{
try
{
List<Article> articleList = new List<Article>();
articleList = await CollectionHttpClient.GetArticlesByPageAsync(pageNumber);
foreach (var item in articleList)
{
item.BitImage = await CollectionHttpClient.GetWebImageByImageName(item.ImagePathList[0]);
this.ArticleCollection.Add(item);
}
IsLoading = false;
}
catch(Exception ex)
{
if (ex.HResult == -2146233088 && ex.Message.Equals("Response status code does not indicate success: 404 ()."))
{
MessageBox.Show("The network is not set right. Internet cannot be accessed.");
}
else
{
MessageBox.Show("sorry, no data.");
}
IsLoading = false;
}
}
Model is:
public class Article : INotifyPropertyChanged
{
private long _Id;
public long ID
{
get { return _Id; }
set
{
if (_Id != value)
{
_Id = value;
NotifyPropertyChanged("ID");
}
}
}
private string _subject;
public string Subject
{
get
{
return _subject;
}
set
{
if (_subject != value)
{
_subject = value;
NotifyPropertyChanged("Subject");
}
}
}
private string _words;
public string Words
{
get
{
return _words;
}
set
{
if (_words != value)
{
_words = value;
NotifyPropertyChanged("Words");
}
}
}
private DateTime _publishDate;
public DateTime PublishDate
{
get
{ return _publishDate; }
set
{
if (_publishDate != value)
{
_publishDate = value;
NotifyPropertyChanged("PublishDate");
}
}
}
private ObservableCollection<string> _imagePathList = new ObservableCollection<string>();
public ObservableCollection<string> ImagePathList
{
get { return this._imagePathList; }
set
{
if (this._imagePathList != value)
{
this._imagePathList = value;
// I'm going to assume you have the NotifyPropertyChanged
// method defined on the view-model
this.NotifyPropertyChanged();
}
}
}
BitmapImage _image;
public BitmapImage BitImage
{
get
{
return _image;
}
set
{
if (ImagePathList.Any())
{
value = new BitmapImage(new Uri(ImagePathList.FirstOrDefault(), UriKind.RelativeOrAbsolute));
_image = value;
}
}
}
private Uri _firstImage;
public Uri FirstImage
{
get
{
return _firstImage;
}
set
{
if (_firstImage != value)
{
_firstImage = value;
NotifyPropertyChanged("FirstImage");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
First if you have the url you can give url to the binding paramter and it will automatically show the image or if you want to download the image and save it & then display it so here is the code for byte to image & image to byte.
{
BitmapImage image = new BitmapImage();
MemoryStream ms = new MemoryStream();
WriteableBitmap wb = new WriteableBitmap(image);
wb.SaveJpeg(ms, image.PixelWidth, image.PixelHeight, 0, 100);
imageBytes = ms.ToArray();
}
Use this to save image because i am using it my code.
Related
In perl there's a rather simple method of tying a data structure to a file, whether it be a string, hash(dictionary in C#) or a simple array/list.
I've cobbled together my own half-assed solution in C# but I was wondering if there's a more inbuilt way to achieve this functionality?
Edit in response to comment below--The question, directly: Is there an inbuilt way to "tie" a class/dictionary to a file so any changes in either is reflected in the other? (Without doing as I've done below)
(Tieing a dictionary means that any changes in the dictionary are immediately reflected/updated in the file and declaring a tied var loads the object from disk if it already exists; see PerlTie )
My pseudo-tie'd class is below:
#region options
private float _Opacity;
public float Opacity {
get {
return Opacity;
}
set {
_Opacity = value;
this.Save();
}
}
private Font _Font;
public Font Font {
get {
return _Font;
}
set {
_Font = value;
this.Save();
}
}
private Color _FontColor;
public Color FontColor {
get {
return _FontColor;
}
set {
_FontColor = value;
this.Save();
}
}
private Color _BGColor;
public Color BGColor {
get {
return _BGColor;
}
set {
_BGColor = value;
this.Save();
}
}
private Point _Location;
public Point Location {
get {
return _Location;
}
set {
_Location = value;
this.Save();
}
}
private Size _Size;
public Size Size {
get {
return _Size;
}
set {
_Size = value;
this.Save();
}
}
private ushort _HistoryLines;
public ushort HistoryLines {
get {
return _HistoryLines;
}
set {
_HistoryLines = value;
this.Save();
}
}
private ChatType _ChatModes;
public ChatType ChatModes {
get {
return _ChatModes;
}
set {
_ChatModes = value;
this.Save();
}
}
private bool _Debugging;
public bool Debugging {
get {
return _Debugging;
}
set {
_Debugging = value;
this.Save();
}
}
#endregion options
private FontConverter FontConvert;
private FileInfo SettingsFile;
private MLogConf() {
}
public MLogConf(string stateFile) {
FontConvert = new FontConverter();
try {
if (!Directory.Exists(Path.GetDirectoryName(stateFile)))
Directory.CreateDirectory(Path.GetDirectoryName(stateFile));
if (!File.Exists(stateFile)) {
FileStream fs = File.Create(stateFile);
fs.Close();
}
SettingsFile = new FileInfo(stateFile);
if (SettingsFile.Length == 0) {
this.SetDefaultOptions();
} else {
if (!this.Load()) {
throw new FileLoadException("Couldn't load settings file");
}
}
} catch (Exception ex) {
Trace.Write($"Failed to create MLogConf({nameof(stateFile)}) {ex.Message + Environment.NewLine + ex.StackTrace}");
}
}
private bool Load() {
if (SettingsFile == null)
return false;
try {
byte[] data = File.ReadAllBytes(SettingsFile.FullName);
using (MemoryStream m = new MemoryStream(data)) {
using (BinaryReader reader = new BinaryReader(m)) {
_Opacity = reader.ReadSingle();
_Font = (Font)(FontConvert.ConvertFromString(Encoding.ASCII.GetString(Convert.FromBase64String(reader.ReadString()))));
_FontColor = Color.FromArgb(reader.ReadInt32());
_BGColor = Color.FromArgb(reader.ReadInt32());
_Location = new Point(reader.ReadInt32(), reader.ReadInt32());
_Size = new Size(reader.ReadInt32(), reader.ReadInt32());
_HistoryLines = reader.ReadUInt16();
_ChatModes = (ChatType)reader.ReadInt32();
_Debugging = reader.ReadBoolean();
}
}
} catch (Exception e) {
Trace.WriteLine($"Exception reading binary data: {e.Message + Environment.NewLine + e.StackTrace}");
return false;
}
return true;
}
private bool Save() {
try {
using (FileStream fs = new FileStream(SettingsFile.FullName, FileMode.Create)) {
using (BinaryWriter writer = new BinaryWriter(fs)) {
writer.Write(_Opacity);
writer.Write(Convert.ToBase64String(Encoding.ASCII.GetBytes((string)FontConvert.ConvertTo(Font, typeof(string)))));
writer.Write(_FontColor.ToArgb());
writer.Write(_BGColor.ToArgb());
writer.Write(_Location.X);
writer.Write(_Location.Y);
writer.Write(_Size.Width);
writer.Write(_Size.Height);
writer.Write(_HistoryLines);
writer.Write((int)_ChatModes);
writer.Write(_Debugging);
}
}
} catch (Exception e) {
Trace.WriteLine($"Exception writing binary data: {e.Message + Environment.NewLine + e.StackTrace}");
return false;
}
return true;
}
private bool SetDefaultOptions() {
this._BGColor = Color.Black;
this._ChatModes = ChatType.Alliance | ChatType.Emote | ChatType.FreeCompany | ChatType.Linkshell | ChatType.Party | ChatType.SayShoutYell | ChatType.Tell;
this._Opacity = 1f;
this._Font = new Font("Verdana", 50);
this._FontColor = Color.CornflowerBlue;
this._Location = new Point(100, 400);
this._Size = new Size(470, 150);
this._HistoryLines = 512;
this._Debugging = false;
return this.Save();
}
I suppose you are looking for an easy way to store class instances in files.
Serialization is the process of converting an object into a stream of bytes in order to store the object or transmit it to memory, a database, or a file. Its main purpose is to save the state of an object in order to be able to recreate it when needed. The reverse process is called deserialization.
The shortest solution I've found for C# here some time ago was Json.NET from Newtonsoft, available as NuGet package. It will do all the 'long class-properties-to-string code' for you and leave you with string ready to be written in file.
Official site can provide code examples: http://www.newtonsoft.com/json
Save to file:
Product product = new Product();
product.Name = "Apple";
product.Expiry = new DateTime(2008, 12, 28);
product.Sizes = new string[] { "Small" };
string json = JsonConvert.SerializeObject(product);
// {
// "Name": "Apple",
// "Expiry": "2008-12-28T00:00:00",
// "Sizes": [
// "Small"
// ]
// }
Read from file:
string json = #"{
'Name': 'Bad Boys',
'ReleaseDate': '1995-4-7T00:00:00',
'Genres': [
'Action',
'Comedy'
]
}";
Movie m = JsonConvert.DeserializeObject<Movie>(json);
string name = m.Name;
// Bad Boys
I want to get image as byte array from database using local WCF service and display it on a Page using Image control. I cannot make it working.
This is the simplest code just to start… Eventually I want to use binding in XAML.
//I use following code for getting bytes (it’ s working)
private async Task GetPhotoAsync(string code)
{
using (var httpClient = new HttpClient())
{
using (var request = new HttpRequestMessage(HttpMethod.Get,
$"http://192.168.0.5/Service/TerminalService.svc/GetPhoto?Code={code}"))
{
using (var response = await httpClient.SendAsync(request))
{
if (response.IsSuccessStatusCode)
{
ImageBuffer = (await response.Content.ReadAsByteArrayAsync());
}
else
{
throw new Exception($"Error.{Environment.NewLine}{response}");
}
}
}
}
}
...
public byte[] ImageBuffer
{
get { return _imageBuffer; }
set { SetProperty(ref imageBuffer, value); }
}
public class BindableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null)
{
if (object.Equals(storage, value)) return false;
storage = value;
this.OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var eventHandler = this.PropertyChanged;
if (eventHandler != null) eventHandler(this, new PropertyChangedEventArgs(propertyName));
}
}
...
//Method used to convert bytes into BitmapImage and set source of control Image.
public async void SetImageFromByteArray(byte[] data, Image image)
{
using (InMemoryRandomAccessStream raStream = new InMemoryRandomAccessStream())
{
using (DataWriter writer = new DataWriter(raStream))
{
// Write the bytes to the stream
writer.WriteBytes(data);
// Store the bytes to the MemoryStream
await writer.StoreAsync();
// Not necessary, but do it anyway
await writer.FlushAsync();
// Detach from the Memory stream so we don't close it
writer.DetachStream();
}
raStream.Seek(0);
BitmapImage bitMapImage = new BitmapImage();
bitMapImage.SetSource(raStream);
image.Source = bitMapImage;
}
}
When MainPage is loaded I run method GetPhotoAsync().
After a while I set Image.Source by pressing button and run method SetImageFromByteArray().
Nothing is displayed.
I also tried these solutions without success:
with binding properties -
https://marcominerva.wordpress.com/2013/04/15/how-to-convert-a-byte-array-to-image-in-a-windows-store-app/
using converter -
Windows Phone 8 - Load byte[] array into XAML image with Binding
TaskCompletionNotifier -
Async Implementation of IValueConverter
You can try this, it works for me.
First you have to set up property in your ViewModel which you bind the Image control to.
public BitmapImage ImageSource
{
get { return _imageSource; }
set { SetProperty(ref _imageSource, value); }
}
...
public async Task GetPhotoAsync(string twrKod)
{
using (var httpClient = new HttpClient())
{
using (var request = new HttpRequestMessage(HttpMethod.Get,
$"http://192.168.0.5/Service/TerminalService.svc/GetPhoto?Code={code}"))
{
using (var response = await httpClient.SendAsync(request))
{
if (response.IsSuccessStatusCode)
{
var imageStream = await response.Content.ReadAsStreamAsync();
var memStream = new MemoryStream();
await imageStream.CopyToAsync(memStream);
memStream.Position = 0;
var bitmap = new BitmapImage();
bitmap.SetSource(memStream.AsRandomAccessStream())
ImageSource = bitmap;
}
}
}
}
}
Make sure you have MemoryStream to be return type of WCF Service. For example:
public Stream GetPhoto(string code)
{
byte[] bytes = null;
var myCommand = new SqlCommand())
myCommand.Connection = new SqlConnection(Settings.Default.ConnectionString);
objSql.ObjCommand.CommandText = "dbo.GetPhotoProc";
objSql.ObjCommand.CommandType = CommandType.StoredProcedure;
objSql.ObjCommand.Parameters.Add("#code", SqlDbType.NVarChar).Value = code;
objSql.Reader = objSql.ObjCommand.ExecuteReader();
if (!objSql.Reader.HasRows) return null;
while (objSql.Reader.Read())
{
bytes = (byte[])objSql.Reader.GetValue(0);
}
if (bytes == null) return Stream.Null;
var ms = new MemoryStream(bytes) { Position = 0 };
if (WebOperationContext.Current != null)
WebOperationContext.Current.OutgoingResponse.ContentType = "image/jpeg";
return ms;
}
Interface for WCF
[WebGet(UriTemplate = "GetPhoto?Code={code}", RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Bare)]
[OperationContract]
Stream GetPhoto(string code);
I am trying to get the underlying image data from when you select a picture. The function itself with the cameraalbum and selecting a picture works perfectly and I am only missing one thing and that is to get the image data. The imagedata is inside the returned mediaFile i assume but I am not sure how I can reach it on my contentPage.
(I use this project: https://github.com/XLabs/Xamarin-Forms-Labs/wiki/Camera )
The idea is to send the imagedata to my database on the contentpage.
This is the viewmodel named "CameraViewModel":
public async Task SelectPicture()
{
Setup ();
ImageSource = null;
try
{
var mediaFile = await _Mediapicker.SelectPhotoAsync(new CameraMediaStorageOptions
{
DefaultCamera = CameraDevice.Front,
MaxPixelDimension = 400
});
VideoInfo = mediaFile.Path;
ImageSource = ImageSource.FromStream(() => mediaFile.Source);
}
catch (System.Exception ex)
{
Status = ex.Message;
}
}
On my contentpage right now I have this:
CameraViewModel cameraOps = null;
public PhotoPage ()
{
InitializeComponent ();
cameraOps = new CameraViewModel ();
cameraOps. //trying to reach the mediafile here
}
Updated code:
private MediaFile _file;
public MediaFile File
{
get { return _file; }
set
{
_file = value;
}
}
public async Task SelectPicture()
{
Setup ();
ImageSource = null;
try
{
File = await _Mediapicker.SelectPhotoAsync(new CameraMediaStorageOptions
{
DefaultCamera = CameraDevice.Front,
MaxPixelDimension = 400
});
VideoInfo = File.Path;
ImageSource = ImageSource.FromStream(() => File.Source);
}
catch (System.Exception ex)
{
Status = ex.Message;
}
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
File = value as MediaFile;
return ImageSource.FromStream(() => File.Source);
}
You could create property on view model:
private MediaFile _file;
public MediaFile File
{
get { return _file; }
set
{
_file = value;
OnPropertyChanged();
}
}
And then bind it on ContentPage:
<Image Source="{Binding File}, Converter={StaticResource MediaFileToImageSourceConverter}">
Converter:
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var file = value as MediaFile;
return ImageSource.FromStream(() => file.GetStream()));
}
Updated code: (not in best traditions of mvvm, but for your sample)
public async Task<MediaFile> SelectPicture()
{
Setup();
MediaFile file = null;
try
{
file = await _Mediapicker.SelectPhotoAsync(new CameraMediaStorageOptions
{
DefaultCamera = CameraDevice.Front,
MaxPixelDimension = 400
});
}
catch (System.Exception ex)
{
Status = ex.Message;
}
return file;
}
On code behind:
public async void OnTakePhotoButtonClicked(object sender, EventArgs args)
{
var file = await cameraOps.SelectPicture();
someImage.ImageSource = ImageSource.FromStream(() => file.Source);
}
Using XLABS in my xamarin forms project and I try to reach the underlying data of the image but I am not sure how to get it with my current code. I have a viewmodel and a page where I use the function and the function itself works fine. I can pick an image and get it. But I want to get the path/filedata.
My viewmodel:
public ImageSource ImageSource
{
get { return _ImageSource; }
set { SetProperty (ref _ImageSource, value); }
}
private byte[] imageData;
public byte[] ImageData { get { return imageData; } }
private byte[] ReadStream(Stream input)
{
byte[] buffer = new byte[16*1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
public async Task SelectPicture()
{
Setup ();
ImageSource = null;
try
{
var mediaFile = await _Mediapicker.SelectPhotoAsync(new CameraMediaStorageOptions
{
DefaultCamera = CameraDevice.Front,
MaxPixelDimension = 400
});
VideoInfo = mediaFile.Path;
ImageSource = ImageSource.FromStream(() => mediaFile.Source);
}
catch (System.Exception ex)
{
Status = ex.Message;
}
}
private static double ConvertBytesToMegabytes(long bytes)
{
double rtn_value = (bytes / 1024f) / 1024f;
return rtn_value;
}
My page where I use it:
MyViewModel photoGallery = null;
photoGallery = new MyViewModel ();
private async void btnPickPicture_Clicked (object sender, EventArgs e)
{
await photoGallery.SelectPicture ();
imgPicked.Source = photoGallery.ImageSource; //imgPicked is my image x:name from XAML.
}
MediaFile has a Path property. You even refer to it in your ViewModel
VideoInfo = mediaFile.Path;
Scenario:
I have a program which uses a simple class to generate game data. Using the said program, I write the data out using serialization and BinaryFormatter to a file to be used by a second program. Reading the data from this initial program works without issue.
Problem:
It's probably down to my ignorance to how serialized files are handled, but I cannot then load this data into a second program, the actual game itself.
saveGame code (in program 1):
static List<GameData> gameData;
static GameData currentData;
private void saveGame(Sudoku sdk) {
BinaryFormatter bf = new BinaryFormatter();
FileStream file = null;
try {
if(!File.Exists(gameDataFile[currentDifficulty])) {
file = File.Open(gameDataFile[currentDifficulty], FileMode.CreateNew);
} else {
file = File.Open(gameDataFile[currentDifficulty], FileMode.Append);
}
currentData = setGameData(sdk);
bf.Serialize(file, currentData);
savePuzzleLog();
} catch(Exception e) {
Debug.LogException("saveGame", e);
}
if(file != null) {
file.Close();
}
}
loadGameData: (in program 2)
public static List<GameData> gameData;
public bool loadGameData() {
if(gameData == null) {
gameData = new List<GameData>();
} else {
gameData.Clear();
}
bool loadData = true;
bool OK = false;
if(File.Exists(gameDataFile[currentDifficulty])) {
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Open(gameDataFile[currentDifficulty], FileMode.Open);
while(loadData) {
try {
GameData gd = new GameData();
gd = (GameData)bf.Deserialize(file);
gameData.Add(gd);
OK = true;
if(file.Position == file.Length) {
loadData = false;
}
} catch(Exception e) {
Debug.LogException(e);
loadData = false;
OK = false;
}
}
if(file != null) {
file.Close();
}
} else {
Debug.LogWarning(gameDataFile[currentDifficulty] + " does not exist!");
}
return OK;
}
GameData Class: (1st program)
[Serializable]
class GameData {
private int gameID;
private List<int> contentArray;
private int difficultyValue;
public GameData(List<int> data = null) {
id = -1;
difficulty = -1;
if(content != null) {
content.Clear();
} else {
content = new List<int>();
}
if(data != null) {
foreach(int i in data) {
content.Add(i);
}
}
}
public int id {
get {
return this.gameID;
}
set {
this.gameID = value;
}
}
public int difficulty {
get {
return this.difficultyValue;
}
set {
this.difficultyValue = value;
}
}
public List<int> content {
get {
return this.contentArray;
}
set {
this.contentArray = value;
}
}
}
GameData Class: (2nd program) The only difference is declaring as public
[Serializable]
public class GameData {
private int gameID;
private List<int> contentArray;
private int difficultyValue;
public GameData(List<int> data = null) {
id = -1;
difficulty = -1;
if(content != null) {
content.Clear();
} else {
content = new List<int>();
}
if(data != null) {
foreach(int i in data) {
content.Add(i);
}
}
}
public int id {
get {
return this.gameID;
}
set {
this.gameID = value;
}
}
public int difficulty {
get {
return this.difficultyValue;
}
set {
this.difficultyValue = value;
}
}
public List<int> content {
get {
return this.contentArray;
}
set {
this.contentArray = value;
}
}
}
What my question is, is how do I save the data out in one program and be able to load it using a different program without getting serialization errors or do I need to use an alternate save/load method and/or class structure?
When I had to do it i made it this way :
An independant dll (assembly) containing the class holding the data (for you the GameData class), and utility methods to save/load from a file.
Your two other projects must then reference this dll (assembly) and you should be able to (de)serialize correctly.
What I think the issue is in your case is that the BinaryFormatter does not only save the data in the file, but also the complete Type of the serialized object.
When you try to deserialize in another similar object, even if the structure is the same, the full name of the class is not (because the assembly name is not).
OK, I've sorted it using the advice given. Instead of using BinaryFormatter I have used BinaryWriter and BinaryReader as follows...
In program 1 (the creator):
private byte[] setByteData(Sudoku sdk) {
List<int> clues = sdk.puzzleListData();
byte[] bd = new byte[puzzleSize];
SudokuSolver solver = new SudokuSolver();
List<int> solution = solver.Solve(sdk.Copy(), false, currentDifficulty).puzzleListData();
for(int i = 0; i < puzzleSize; i++) {
bd[i] = Convert.ToByte(solution[i] + (clues[i] == 0 ? 0xF0 : 0));
}
return bd;
}
private GameData setGameData(Sudoku sdk) {
List<int> clues = sdk.puzzleListData();
GameData gd = new GameData();
gd.id = puzzleList.Items.Count;
gd.difficulty = currentDifficulty;
SudokuSolver solver = new SudokuSolver();
List<int> solution = solver.Solve(sdk.Copy(), false, currentDifficulty).puzzleListData();
for(int i = 0; i < puzzleSize; i++) {
gd.content.Add(solution[i] + (clues[i] == 0 ? 0xF0 : 0));
}
return gd;
}
private List<int> getByteData(byte[] data) {
List<int> retVal = new List<int>();
foreach(byte i in data) {
if(i > 9) {
retVal.Add(i - 0xF0);
} else {
retVal.Add(0);
}
}
return retVal;
}
private string getGameData(List<int> data) {
string retVal = "";
foreach(int i in data) {
if(i > 9) {
retVal += (i - 0xF0).ToString();
} else {
retVal += i.ToString();
}
}
return retVal;
}
private void saveGame(Sudoku sdk) {
FileStream file = null;
BinaryWriter bw = null;
try {
if(!File.Exists(gameDataFile[currentDifficulty])) {
file = File.Open(gameDataFile[currentDifficulty], FileMode.CreateNew);
} else {
file = File.Open(gameDataFile[currentDifficulty], FileMode.Append);
}
bw = new BinaryWriter(file);
currentData = setGameData(sdk);
byte[] bd = setByteData(sdk);
bw.Write(currentData.id);
bw.Write(currentData.difficulty);
bw.Write(bd);
savePuzzleLog();
} catch(Exception e) {
Debug.LogException("saveGame", e);
}
if(file != null) {
if(bw != null) {
bw.Flush();
bw.Close();
}
file.Close();
}
}
In program 2: (the actual game)
public bool loadGameData() {
if(gameData == null) {
gameData = new List<GameData>();
} else {
gameData.Clear();
}
bool loadData = true;
bool OK = false;
if(File.Exists(gameDataFile[currentDifficulty])) {
FileStream file = File.Open(gameDataFile[currentDifficulty], FileMode.Open);
BinaryReader br = new BinaryReader(file);
while(loadData) {
try {
GameData gd = new GameData();
gd.id = br.ReadInt32();
gd.difficulty = br.ReadInt32();
gd.content = getByteData(br.ReadBytes(puzzleSize));
gameData.Add(gd);
OK = true;
if(file.Position == file.Length) {
loadData = false;
}
} catch(Exception e) {
Debug.LogException(e);
loadData = false;
OK = false;
}
}
if(file != null) {
file.Close();
}
} else {
Debug.LogWarning(gameDataFile[currentDifficulty] + " does not exist!");
}
return OK;
}
The class structure is the same as before but using this method has resolved my issue and I can now create the data files using my creator and load the data comfortably using the actual game.
Thanks all for your assistance and advice to help me get this sorted.