I'm using Reflection to load some values from an XML into a structure. All works but I got a problem to manage the array. With an Int32 it's ok, but how can I manage an Int32[]?
EDIT: Here's my code ... it's not complete due the lenght ... I want to improve the save and load for the array types.
//My struct ... it should be a class too
public struct stOptions
{
public int IntNumber;
public double DoubleNumber;
public string String;
public Point aPoint;
}
//How my class works
private void Form1_Load(object sender, EventArgs e)
{
stOptions options = new stOptions();
//Populate the struct
options.aPoint = new Point(12, 24);
options.DoubleNumber = 34d;
options.IntNumber = 17;
options.String = "Hello";
ManageSettings ms = new ManageSettings();
ms.SaveSettings("e:\\test001.xml", options);
options = default(stOptions);
options = ms.LoadSettings<stOptions>("e:\\test001.xml");
}
//A portion of my class
public T LoadSettings<T>(string FileName)
{
Type type = typeof(T);
var returnObject = Activator.CreateInstance(type);
List<Settings> list = null;
try
{
using (StreamReader reader = File.OpenText(FileName))
{
XmlSerializer serializer = new XmlSerializer(typeof(List<Settings>));
list = (List<Settings>)serializer.Deserialize(reader);
}
}
catch
{
//Error accessing the file
_errors.Add("Unable to locate the file or access denied: " + FileName);
return default(T);
}
try
{
foreach (Settings entry in list)
{
FieldInfo field = returnObject.GetType().GetField(entry.Key.ToString());
if (field != null)
{
SetField(field, entry.Value.ToString(), returnObject);
}
field = null;
PropertyInfo prop = returnObject.GetType().GetProperty(entry.Key.ToString());
if (prop != null)
{
SetField(prop, entry.Value.ToString(), returnObject);
}
prop = null;
}
list = null;
}
catch
{
//Error processing the XML
_errors.Add("Errore processing the XML file: " + FileName);
return default(T);
}
return (T)returnObject;
}
private void SetField(FieldInfo prop, string value, object returnObject)
{
switch (prop.FieldType.Name.ToLower())
{
case "uint16":
prop.SetValue(returnObject, Convert.ToUInt16(value));
break;
case "uint32":
prop.SetValue(returnObject, Convert.ToUInt32(value));
break;
etc.
[...]
default:
//An unmanaged type
Debug.WriteLine("Found an unmanaged type: " + prop.FieldType.Name);
break;
}
}
When it is completed I will publish it.
Related
While exploring Roslyn I put together a small app that should include a trace statement as the first statement in every method found in a Visual Studio Solution. My code is buggy and is only updating the first method.
The line that is not working as expected is flagged with a “TODO” comment. Please, advise.
I also welcome style recommendations that would create a more streamlined/readable solution.
Thanks in advance.
...
private void TraceBtn_Click(object sender, RoutedEventArgs e) {
var myWorkSpace = new MyWorkspace("...Visual Studio 2012\Projects\Tests.sln");
myWorkSpace.InjectTrace();
myWorkSpace.ApplyChanges();
}
...
using System;
using System.Linq;
using Roslyn.Compilers;
using Roslyn.Compilers.CSharp;
using Roslyn.Services;
namespace InjectTrace
{
public class MyWorkspace
{
private string solutionFile;
public string SolutionFile {
get { return solutionFile; }
set {
if (string.IsNullOrEmpty(value)) throw new Exception("Invalid Solution File");
solutionFile = value;
}
}
private IWorkspace loadedWorkSpace;
public IWorkspace LoadedWorkSpace { get { return loadedWorkSpace; } }
public ISolution CurrentSolution { get; private set; }
public IProject CurrentProject { get; private set; }
public IDocument CurrentDocument { get; private set; }
public ISolution NewSolution { get; private set; }
public MyWorkspace(string solutionFile) {
this.SolutionFile = solutionFile;
this.loadedWorkSpace = Workspace.LoadSolution(SolutionFile);
}
public void InjectTrace()
{
int projectCtr = 0;
int documentsCtr = 0;
int transformedMembers = 0;
int transformedClasses = 0;
this.CurrentSolution = this.LoadedWorkSpace.CurrentSolution;
this.NewSolution = this.CurrentSolution;
//For Each Project...
foreach (var projectId in LoadedWorkSpace.CurrentSolution.ProjectIds)
{
CurrentProject = NewSolution.GetProject(projectId);
//..for each Document in the Project..
foreach (var docId in CurrentProject.DocumentIds)
{
CurrentDocument = NewSolution.GetDocument(docId);
var docRoot = CurrentDocument.GetSyntaxRoot();
var newDocRoot = docRoot;
var classes = docRoot.DescendantNodes().OfType<ClassDeclarationSyntax>();
IDocument newDocument = null;
//..for each Class in the Document..
foreach (var #class in classes) {
var methods = #class.Members.OfType<MethodDeclarationSyntax>();
//..for each Member in the Class..
foreach (var currMethod in methods) {
//..insert a Trace Statement
var newMethod = InsertTrace(currMethod);
transformedMembers++;
//TODO: PROBLEM IS HERE
newDocRoot = newDocRoot.ReplaceNode(currMethod, newMethod);
}
if (transformedMembers != 0) {
newDocument = CurrentDocument.UpdateSyntaxRoot(newDocRoot);
transformedMembers = 0;
transformedClasses++;
}
}
if (transformedClasses != 0) {
NewSolution = NewSolution.UpdateDocument(newDocument);
transformedClasses = 0;
}
documentsCtr++;
}
projectCtr++;
if (projectCtr > 2) return;
}
}
public MethodDeclarationSyntax InsertTrace(MethodDeclarationSyntax currMethod) {
var traceText =
#"System.Diagnostics.Trace.WriteLine(""Tracing: '" + currMethod.Ancestors().OfType<NamespaceDeclarationSyntax>().Single().Name + "." + currMethod.Identifier.ValueText + "'\");";
var traceStatement = Syntax.ParseStatement(traceText);
var bodyStatementsWithTrace = currMethod.Body.Statements.Insert(0, traceStatement);
var newBody = currMethod.Body.Update(Syntax.Token(SyntaxKind.OpenBraceToken), bodyStatementsWithTrace,
Syntax.Token(SyntaxKind.CloseBraceToken));
var newMethod = currMethod.ReplaceNode(currMethod.Body, newBody);
return newMethod;
}
public void ApplyChanges() {
LoadedWorkSpace.ApplyChanges(CurrentSolution, NewSolution);
}
}
}
The root problem of you code is that newDocRoot = newDocRoot.ReplaceNode(currMethod, newMethod); somehow rebuilds newDocRoot internal representation of code so next currMethod elements won't be find in it and next ReplaceNode calls will do nothing. It is a situation similar to modifying a collection within its foreach loop.
The solution is to gather all necessary changes and apply them at once with ReplaceNodes method. And this in fact naturally leads to simplification of code, because we do not need to trace all those counters. We simply store all needed transformation and apply them for whole document at once.
Working code after changes:
public void InjectTrace()
{
this.CurrentSolution = this.LoadedWorkSpace.CurrentSolution;
this.NewSolution = this.CurrentSolution;
//For Each Project...
foreach (var projectId in LoadedWorkSpace.CurrentSolution.ProjectIds)
{
CurrentProject = NewSolution.GetProject(projectId);
//..for each Document in the Project..
foreach (var docId in CurrentProject.DocumentIds)
{
var dict = new Dictionary<CommonSyntaxNode, CommonSyntaxNode>();
CurrentDocument = NewSolution.GetDocument(docId);
var docRoot = CurrentDocument.GetSyntaxRoot();
var classes = docRoot.DescendantNodes().OfType<ClassDeclarationSyntax>();
//..for each Class in the Document..
foreach (var #class in classes)
{
var methods = #class.Members.OfType<MethodDeclarationSyntax>();
//..for each Member in the Class..
foreach (var currMethod in methods)
{
//..insert a Trace Statement
dict.Add(currMethod, InsertTrace(currMethod));
}
}
if (dict.Any())
{
var newDocRoot = docRoot.ReplaceNodes(dict.Keys, (n1, n2) => dict[n1]);
var newDocument = CurrentDocument.UpdateSyntaxRoot(newDocRoot);
NewSolution = NewSolution.UpdateDocument(newDocument);
}
}
}
}
I have objects in Autocad drawing with property named Base. I am trying to find all objects in that drawing with Base property has a specific string value such as "Pipe".
I can iterate objects in the drawing and get all object ids. Then I get all properties of object with that Id and check if property named Base = "Pipe".
Iteration performance is not good enough. Is there any way to directly get object ids that has property named Base = "Pipe"?
Here is how I iterate through all objects:
List<ObjectId> ObjectIds = new List<ObjectId>();
foreach (Document Document in Documents)
{
Database Database = Document.Database;
using (Transaction Transaction = Database.TransactionManager.StartTransaction())
{
for (long i = Database.BlockTableId.Handle.Value; i < Database.Handseed.Value; i++)
{
ObjectId Id;
if (Database.TryGetObjectId(new Handle(i), out Id))
{
ObjectIds.Add(Id);
}
}
Transaction.Commit();
}
}
And here is how I get all properties of the objects in my ObjectIds collection.
public static DataLinksManager DataLinks
{
get
{
if (null == _DataLinks)
{
StringCollection Coll = Autodesk.ProcessPower.DataLinks.DataLinksManager.GetLinkManagerNames();
if (Coll.Count > 0)
{
if (Coll[0] != string.Empty)
{
_DataLinks = Autodesk.ProcessPower.DataLinks.DataLinksManager.GetManager(Coll[0]);
}
}
}
return _DataLinks;
}
}
private static DataLinksManager _DataLinks;
foreach(var Id in ObjectIds)
{
List<KeyValuePair<string, string>> Properties = DataLinks.GetAllProperties(Id, true);
// I check existence of my property and if so its value.
}
In case anyone needs, here is the code that is solution to my problem. The trick is the Iterate method. This is based on this article by Philippe Leefsma. What I add to this method is a list of ObjectClass properties of found ObjectId instances. My sample dawing has around 8500 ObjectIds. However what I'm interested in is objects with base classes acppasset and acppdynamicasset and count of such objects is 90.
using Autodesk.AutoCAD.ApplicationServices;
using AcadApp = Autodesk.AutoCAD.ApplicationServices.Application;
public static void GetObjects()
{
List<KeyValuePair<string, ObjectId>> ObjectIds = new List<KeyValuePair<string, ObjectId>>();
List<string> Filter = new List<string>() { "acppasset", "acppdynamicasset" };
foreach (Document Document in this.Documents)
{
ObjectIdCollection Ids = this.Iterate(Document, Filter);
if (null != Ids) foreach (var Id in Ids.OfType<ObjectId>()) ObjectIds.Add(new KeyValuePair<string, ObjectId>(System.IO.Path.GetFileNameWithoutExtension(Document.Name), Id));
}
this.Results = new Dictionary<string, List<List<KeyValuePair<string, string>>>>();
foreach (var Id in ObjectIds)
{
try
{
var Properties = this.GetObject(Id.Value);
if (null == Properties) continue;
var Base = Properties.Where(x => x.Key == "Base").FirstOrDefault();
if (string.IsNullOrWhiteSpace(Base.Value)) continue;
if (!this.Results.ContainsKey(Base.Value)) this.Results.Add(Base.Value, new List<List<KeyValuePair<string, string>>>());
this.Results[Base.Value].Add(Properties);
} catch { }
}
}
public ObservableCollection<Document> Documents { get; set; }
public ObjectIdCollection Iterate(Document Document, List<string> Filter = null)
{
ads_name Instance = new ads_name();
Database Database = Document.Database;
ObjectIdCollection ValidIds = new ObjectIdCollection();
// Get the last handle in the Database
Handle Handseed = Database.Handseed;
// Copy the handseed total into an efficient raw datatype
long HandseedTotal = Handseed.Value;
for (long i = 1; i < HandseedTotal; ++i)
{
string Handle = Convert.ToString(i, 16);
int Result = acdbHandEnt(Handle, ref Instance);
if (Result != 5100) continue; // RTNORM
ObjectId Id = new ObjectId(Instance.a);
if (!Id.IsValid) continue;
try
{
if (null != Filter)
{
if (!Filter.Contains(Id.ObjectClass.Name.ToLower())) continue;
}
using (DBObject DBObject = Id.Open(OpenMode.ForRead, false))
{
ValidIds.Add(Id);
DBObject.Dispose();
}
} catch { }
}
return ValidIds;
}
public List<KeyValuePair<string, string>> GetObject(ObjectId Id)
{
if (Command.DataLinks != null) try { return Command.DataLinks.GetAllProperties(Id, true); } catch { return null; }
return null;
}
public static DataLinksManager DataLinks
{
get
{
if (null == _DataLinks)
{
StringCollection Coll = Autodesk.ProcessPower.DataLinks.DataLinksManager.GetLinkManagerNames();
if (Coll.Count > 0)
{
if (Coll[0] != string.Empty)
{
_DataLinks = Autodesk.ProcessPower.DataLinks.DataLinksManager.GetManager(Coll[0]);
}
}
}
return _DataLinks;
}
}
private static DataLinksManager _DataLinks;
public Dictionary<string, List<List<KeyValuePair<string, string>>>> Results { get; set; }
The slow performance here is because it attempts to read all the objects and check if it contains any attribute. As far as I know, the attributes exist only for block references(inserts). So if selection filters are used, we could get direct access to only those records based on the filter criteria.
I found a pretty easy example here using selection filter that selects all blocks with a particular name.
Copying a part of that code for reference. This selects only the block references. You can iterate from here.
TypedValue[] filterlist = new TypedValue[1];
filterlist[0] = new TypedValue(0, "INSERT");
SelectionFilter filter = new SelectionFilter(filterlist);
PromptSelectionResult selRes = ed.SelectAll(filter);
if (selRes.Value.Count != 0)
{
SelectionSet set = selRes.Value;
foreach (ObjectId id in set.GetObjectIds())
{
BlockReference oEnt = (BlockReference)tr.GetObject(id, OpenMode.ForWrite);
//do something with oEnt..;
}
}
If you can add complexities to your filter, you will need to iterate only a very small set.
this is my first question in stackoverflow and I am a beginner in using reflection.
I would like to dump all values of an object instance for reference (to keep track about used values on a test). I am using Compact Framework 3.5 not the full framework. Keep that in mind for your suggestions.
Imagine following classes:
public class Camera : IDisposable
{
public Camera.FilenameProperties SnapshotFile;
public double DigitalZoomFactor { get; set; }
public bool DisplayHistogram { get; set; }
public int ImageUpdateInterval { get; set; }
public Camera.ImprintCaptionPosType ImprintCaptionPos { get; set; }
public string ImprintCaptionString { get; set; }
}
where the 'special' types are:
public class FilenameProperties
{
public string Directory { get; set; }
public string Filename { get; set; }
public Camera.FilenamePaddingType FilenamePadding { get; set; }
public Camera.ImageType ImageFormatType { get; set; }
public Camera.ImageResolutionType ImageResolution { get; set; }
public int JPGQuality { get; set; }
public void Restore();
public void Save();
public enum Fnametype
{
tSnapshot = 0,
tCircularCapture = 1,
}
}
public enum ImprintCaptionPosType
{
Disabled = 0,
LowerRight = 1,
LowerLeft = 2,
LowerCenter = 3,
UpperRight = 4,
UpperLeft = 5,
UpperCenter = 6,
Center = 7,
}
Now, I can get the 'base' names and properties and the field names of an instance of camera:
Camera cam = new Camera();
dumpProperties(cam);
...
void dumpProperties(object oClass)
{
System.Diagnostics.Debug.WriteLine(oClass.ToString());
FieldInfo[] _Info = oClass.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance);
for(int i = 0; i<_Info.Length; i++)
{
System.Diagnostics.Debug.WriteLine(_Info[i].Name + ":'" + _Info[i].GetValue(oClass).ToString()+"'");
}
foreach (PropertyInfo pi in oClass.GetType().GetProperties())
{
System.Diagnostics.Debug.WriteLine(pi.Name + ":'" + pi.GetValue(oClass, null)
+ "' Type=" + pi.PropertyType.ToString());
}
}
and then get soemthing like this:
Intermec.Multimedia.Camera
SnapshotFile:'Intermec.Multimedia.Camera+FilenameProperties'
DigitalZoomFactor:'1' Type=System.Double
DisplayHistogram:'False' Type=System.Boolean
ImageUpdateInterval:'1' Type=System.Int32
ImprintCaptionPos:'Disabled' Type=Intermec.Multimedia.Camera+ImprintCaptionPosType
ImprintCaptionString:'' Type=System.String
Now, for simple properties like DigitalZoomFactor and ImageUpdateInterval I get what I need, but for the nested class (correct wording?) I only get the type as for example with SnapshotFile. For the nested enum I get the value as with 'ImprintCaptionPos'.
How can I get the values of the nested values like FilenameProperties.Filename of the SnapshotFile field/property?
If I use dumpProperties(cam.SnapshotFile), I get the output I am looking for:
Intermec.Multimedia.Camera+FilenameProperties
Directory:'\Program Files\FrmCamera' Type=System.String
Filename:'myphoto' Type=System.String
ImageFormatType:'JPG' Type=Intermec.Multimedia.Camera+ImageType
FilenamePadding:'None' Type=Intermec.Multimedia.Camera+FilenamePaddingType
ImageResolution:'Medium' Type=Intermec.Multimedia.Camera+ImageResolutionType
JPGQuality:'100' Type=System.Int32
But how can I automate that?
I did a lot of search and test coding but was unable to find a solution. The problem seems to be getting the instance of the field to be able to iterate thru it.
I do not have the source code of the Camera class, so I cannot add or remove code in there.
Can anyone help?
I need to get something like the debugger shows:
You simply need to use recursion, and loop back into the method if your property is a class. Here's an example of an XML Serialization routine we use, that effectively walks the properties of a target using reflection, and generates an XElement from it. Your logic would be somewhat different as you're not going to build up XML, but the structure of what you're going to do will be pretty similar.
public XElement Serialize(object source,
string objectName,
bool includeNonPublicProperties)
{
XElement element;
var flags = BindingFlags.Instance | BindingFlags.Public;
if(includeNonPublicProperties)
{
flags |= BindingFlags.NonPublic;
}
var props = source.GetType().GetProperties(flags);
var type = source.GetType();
string nodeName;
if(objectName == null)
{
if (type.IsGenericType)
{
nodeName = type.Name.CropAtLast('`');
}
else
{
nodeName = type.Name;
}
}
else
{
nodeName = objectName;
}
element = new XElement(nodeName);
foreach (var prop in props)
{
string name = prop.Name;
string value = null;
bool valIsElement = false;
if (!prop.CanRead) continue;
if(prop.PropertyType.IsEnum)
{
value = prop.GetValue(source, null).ToString();
}
else
{
string typeName;
if (prop.PropertyType.IsNullable())
{
typeName = prop.PropertyType.GetGenericArguments()[0].Name;
}
else
{
typeName = prop.PropertyType.Name;
}
switch (typeName)
{
case "String":
case "Boolean":
case "Byte":
case "TimeSpan":
case "Single":
case "Double":
case "Int16":
case "UInt16":
case "Int32":
case "UInt32":
case "Int64":
case "UInt64":
value = (prop.GetValue(source, null) ?? string.Empty).ToString();
break;
case "DateTime":
try
{
var tempDT = Convert.ToDateTime(prop.GetValue(source, null));
if (tempDT == DateTime.MinValue) continue;
value = tempDT.ToString("MM/dd/yyyy HH:mm:ss.fffffff");
}
catch(Exception ex)
{
continue;
}
break;
default:
var o = prop.GetValue(source, null);
XElement child;
if (o == null)
{
child = new XElement(prop.Name);
}
else
{
child = Serialize(o, prop.Name, includeNonPublicProperties);
}
element.Add(child);
valIsElement = true;
break;
}
}
if (!valIsElement)
{
element.AddAttribute(name, value);
}
}
return element;
}
OK, I find a way (a workaround) to get all properties (in an XML but who cares) using the code from here:
The output is xml like but acceptable for me. Here an excerpt:
<xml version="1.0" encoding="utf-8">
<Camera xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
...
<ImprintCaptionPos>Disabled</ImprintCaptionPos>
<SnapshotFile>
<Directory>\\Program Files\\FrmCamera</Directory>
<Filename>myphoto</Filename>
<ImageFormatType>JPG</ImageFormatType>
<FilenamePadding>None</FilenamePadding>
<ImageResolution>Medium</ImageResolution>
<JPGQuality>100</JPGQuality>
</SnapshotFile>
...
In my code I just have to call
string s = serialization.mySerialize.SerializeObject<Intermec.Multimedia.Camera>(cam);
To get a 'dump' of all current properties of the instance.
Thanks to all for your help. Possibly I was misunderstood with my question and reflection is unable to give what I want.
Thanks
Josef
You have to do the iteration to all inner object members like you did for outer class. Will be an exercise for you to implement it for complete set of .NET types. Below is the pseudo code of simple implementation
void dumpProperties(object target)
{
if (target.GetType().IsSimple() || target.GetType().IsMethodImplemented("ToString"))
System.Diagnostics.Debug.WriteLine(target.ToString());
else if (target is IEnumerable)
{
foreach (object item in (IEnumerable)target)
{
System.Diagnostics.Debug.WriteLine(dumpProperties(target));
}
}
else
{
foreach (FieldInfo fieldInfo in target.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance))
{
System.Diagnostics.Debug.WriteLine(dumpProperties(fieldInfo.FieldHandle.Value));
}
foreach (PropertyInfo propertyInfo in oClass.GetType().GetProperties())
{
System.Diagnostics.Debug.WriteLine(dumpProperties(propertyInfo.GetGetMethod().MethodHandle.Value));
}
}
}
Or you can use Cinchoo framework, which has built in function to dump any object.
Console.WriteLine(ChoObject.ToString(camera));
In the code that I'm working on, there are some properties that are serialized. All of them works fine as far as I can see, but one. Here's the code:
// Fields that the properties use.
private bool _useAlertColors = false;
private List<Int32> _colorArgb = new List<Int32>(new Int32[]{Color.White.ToArgb(), Color.Yellow.ToArgb(), Color.Red.ToArgb()});
// The one that does not work.
public List<Color> AlertColors
{
get
{
List<Color> alertColors = new List<Color>();
foreach (Int32 colorValue in _colorArgb)
{
alertColors.Add(Color.FromArgb(colorValue));
}
return alertColors;
}
set
{
// If there's any difference in colors
// then add the new color
for (int i = 0; i < _colorArgb.Count; i++)
{
if (_colorArgb[i] != value[i].ToArgb())
{
_colorArgb[i] = value[i].ToArgb();
HasChanged = true;
}
}
}
}
// One of those that work.
public bool UseAlertColors
{
get
{
return _useAlertColors;
}
set
{
if (_useAlertColors != value)
{
_useAlertColors = value;
HasChanged = true;
}
}
}
// Serializing method.
public bool Serialize(string filePath)
{
if (string.IsNullOrEmpty(filePath))
{
Logger.Log("Can't save settings, empty or null file path.");
return false;
}
FileStream fileStream = null;
try
{
fileStream = new FileStream(filePath, FileMode.Create);
FilePath = filePath;
System.Xml.Serialization.XmlSerializerFactory xmlSerializerFactory =
new XmlSerializerFactory();
System.Xml.Serialization.XmlSerializer xmlSerializer =
xmlSerializerFactory.CreateSerializer(typeof(Settings));
xmlSerializer.Serialize(fileStream, this);
Logger.Log("Settings have been saved successfully to the file " + filePath);
}
catch (ArgumentException argumentException)
{
Logger.Log("Error while saving the settings. " + argumentException.Message);
return false;
}
catch (IOException iOException)
{
Logger.Log("Error while saving the settings. " + iOException.Message);
return false;
}
finally
{
if (fileStream != null)
fileStream.Close();
}
return true;
}
After the serialization, this is what I end up with:
<UseAlertColors>true</UseAlertColors>
<AlertColors>
<Color />
<Color />
<Color />
</AlertColors>
What is wrong with the AlertColors property? Why is it not serialized?
Edit: I've changed the AlertColors property accordingly and it still is not working:
public List<int> AlertColors
{
get
{
return _colorArgb;
}
set
{
// If there's any difference in colors
// then add the new color
for (int i = 0; i < _colorArgb.Count; i++)
{
if (_colorArgb[i] != value[i])
{
_colorArgb[i] = value[i];
HasChanged = true;
}
}
}
}
What I get in the .xml file is this:
<AlertColors>
<int>-1</int>
<int>-8355840</int>
<int>-65536</int>
</AlertColors>
Which are the very first values that were set when the _colorArgb field was initialized. I can see the field change during the program execution, but when the covering property is serialized, it is serialized with the initial value of the underlying field.
What is causing the problem?
XMLSerializer only uses public properties of a class when serializing - The Color Class has none.
Heres a good example of how to get around it: http://www.codeproject.com/Articles/2309/NET-XML-Serialization-a-settings-class
Is there anyway to read the specific line?
http://i.stack.imgur.com/hDPIg.jpg
XDocument dataFeed = XDocument.Parse(e.Result);
AchivementsListBox.ItemsSource = from query in dataFeed.Descendants("MaxPayne3")
select new NewGamesClass
{
GameGuide = (string)query.Element("Guide")
};
I would use a single WebClient instance to download the files, and simply reduce it to a single event handler. More than that, you have a similar document structure from what I can tell. That means that you could also re-use your reading code instead of writing it twice.
Something like this:
void Download(GameType type, Action onCompletion)
{
WebClient client = new WebClient();
client.DownloadProgressChanged += (s, args) =>
{
// Handle change in progress.
};
client.DownloadStringCompleted += (s, args) =>
{
XDocument feed = XDocument.Parse(args.Result);
var itemSource = from query in feed.Root
select new NewGamesClass
{
NewGameTitle = (string)query.Element("Title"),
NewGameDescription = (string)query.Element("Descript
NewGameImage = (string)query.Element("Image")
};
switch (type)
{
case GameType.ComingSoon:
{
ComingSoonList.ItemSource = itemSource;
}
case GameType.NewGames:
{
NewGameList.ItemSource = itemSource;
}
}
if (onCompletion != null)
onCompletion();
};
switch (type)
{
case GameType.NewGames:
{
client.DownloadStringAsync(new Uri("http://microsoft.com", UriKind.Absolute));
break;
}
case GameType.ComingSoon:
{
client.DownloadStringAsync(new Uri("http://www.bing.com", UriKind.Absolute));
break;
}
}
}
Although the code might look a bit more complex, it lets you recursively download data when a specific data set is downloaded. Obviously, you would have to declare the GameType enum and I simply used a bunch of test values here to demonstrate the idea.
// It Will Download The XML Once To Use further to Avoid Again And Again Calls For Each Time
public void GetXML(string path)
{
WebClient wcXML = new WebClient();
wcXML.OpenReadAsync(new Uri(path));
wcXML.OpenReadCompleted += new OpenReadCompletedEventHandler(webClient);
}
void webClient(object sender, OpenReadCompletedEventArgs e)
{
if (e.Error == null)
{
try
{
Stream Resultstream = e.Result;
XmlReader reader = XmlReader.Create(Resultstream);
var isolatedfile = IsolatedStorageFile.GetUserStoreForApplication();
using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream("Download.xml", System.IO.FileMode.Create, isolatedfile))
{
byte[] buffer = new byte[e.Result.Length];
while (e.Result.Read(buffer, 0, buffer.Length) > 0)
{
stream.Write(buffer, 0, buffer.Length);
}
stream.Flush();
System.Threading.Thread.Sleep(0);
}
}
catch (Exception ex)
{
//Log Exception
}
}
if (e.Error != null)
{
//Log Exception
}
}
// This Method Will Give You Required Info According To Your Tag Like "Achievement123"
protected List<DownloadInfo> GetDetailFromXML(string TagName)
{
//TagName Like "achivement23"
List<DownloadInfo> listDetails = new List<DownloadInfo>();
XDocument loadedData;
try
{
using (var storage = IsolatedStorageFile.GetUserStoreForApplication())
{
// Check For Islated Storage And Load From That
if (storage.FileExists("Download.xml"))
{
using (Stream stream = storage.OpenFile("Download.xml", FileMode.Open, FileAccess.Read))
{
loadedData = XDocument.Load(stream);
//TagName Like "achivement23"
listDetails.AddRange((from query in loadedData.Element("GOW1").Elements(TagName)
select new DownloadInfo
{
TITLE = (string)query.Element("TITLE"),
DESCRIPTION = (string)query.Element("DESCRIPTION"),
ACHIVEMENTIMAGE = (string)query.Element("ACHIVEMENTIMAGE"),
GUIDE = (string)query.Element("GUIDE"),
YOUTUBELINK = (string)query.Element("YOUTUBELINK")
}).ToList());
}
}
}
return listDetails;
}
catch (Exception ex)
{
return listDetails = null;
//Log Exception
}
}
public class DownloadInfo
{
public string TITLE { get; set; }
public string DESCRIPTION { get; set; }
public string GUIDE { get; set; }
public string ACHIVEMENTIMAGE { get; set; }
public string YOUTUBELINK { get; set; }
}
Here is Your Method Calls
GetXML("ANY URL FROM WHERE YOU WANT TO GET XML"); // You Will Download All The XML Once To Avoid Again And Again Server Calls To Get XML.
GetDetailFromXML("YOUR TAG NAME"); // It Will Take Your Tag Name Which Information You Want To Get Like "Acheicement123" and It Will Return You Data In List<DownloadInfo> and You can easily get data from this List.
I hope it will help you. I didnot Test The Code on Runtime. But I Hope It Will Give You Some Idea.. :)