This is easier explained by codes:
private List<MatchHistory> matchHistories;
public List<MatchHistory> MatchHistories
{
get
{
return matchHistories;
}
set
{
matchHistories = value;
OnPropertyChanged();
}
}
public Command GetMatchHistoriesCmd
{
get;
}
private void ExecuteGetMatchHistories()
{
MatchHistories = Helper.GetMatchHistories(); // This returns List<MatchHistory>
}
Debugging it breaks when it tries to assign to MatchHistories, but why did it gets null when GetMatchHistories returns an object? Shouldn't it just assign that object to the MatchHistories property?
public static List<MatchHistory> GetMatchHistories()
{
List<MatchHistory> mh = new List<MatchHistory>();
mh.Add(new MatchHistory { match_id = "1234", right_win = true });
return mh;
}
Related
How to avoid recursion call in property getter? Here is my simple code
public class UploadAttribute : Attribute
{
private Type _resourceType;
private string _select;
private string _change;
private string _remove;
public Type ResourceType
{
get { return _resourceType; }
set { _resourceType = value; }
}
public string Select
{
get { return GetResourceText(m => m.Select, "Select..."); }
set { _select = value; }
}
public string Change
{
get { return GetResourceText(m => m.Change, "Change..."); }
set { _change = value; }
}
public string Remove
{
get { return GetResourceText(m => m.Remove, "Remove"); }
set { _remove = value; }
}
private string GetResourceText(Expression<Func<UploadAttribute, string>> expression, string #default)
{
var value = expression.Compile().Invoke(this); // here .net is creating new UploadAttribute instance and use it for expression fnc
var result = value ?? #default;
if (_resourceType != null && !string.IsNullOrEmpty(value))
{
ResourceManager rm = new ResourceManager(_resourceType);
try
{
result = rm.GetString(value);
}
catch
{
// if string wasn't found in resource file than use what user specify; don't by big brother.
}
}
return result;
}
}
But if you look at method GetResourceText, there is line where I need to compile and invoke expression to get value for given property. Unfortunately this operation creates new instace of UploadAttribute. In that moment .net goes thru all properties and call getter, if I'm not mistaken, and in getter .net compiles and invokes expression to get value or given property, again, again and again to StackOverlowException.
Can you advice me how to avoid this behavior but with simplicity of this solution?
Edit: The porpose of this class is provide caption for buttons - what user sets with ability to use multi language caption from resource manager.
In example above is button Select translated from Resources, for Change button is used default text "Change..." and for Remove button caption "Destroy this #&#!". So if user doesn't specify property value, application use default text, otherwise try to find text in resources and if match is found than use text from resources else use what user set.
[Required]
[Upload(ResourceType = typeof(Resource), Select = "UploadSelect", Remove = "Destroy this #&#!")]
public HttpPostedFileBase Logo { get; set; }
It appears that what you are trying to achieve is to have some way of initializing these properties if they are not explicitly set. The manner in which you are doing that, will not work.
The m => m.Remove type expressions will cause calling the property getter again in infinite recursion until a stack overflow occurs.
You could use a lazy construct as illustrated below. It works as follows:
If the user does not specify a value for a property, it will return the hard-coded default value when the property getter is invoked.
If the user specifies a value for a property, that value it will be used first as a key in an attempt to retrieve a corresponding string value from the resources. If the resource is not found, it is used as the value for the property, provided that it is not empty, otherwise it will fall back on the hard-coded default value.
Note that this dual purpose for an attribute property value leads to a rather brittle design solution. If a resource with key "UploadSelect" is not found, that will become the caption on the button.
public class UploadAttribute : Attribute
{
private static readonly string kSelectDefaultCaption = "Select...";
private static readonly string kChangeDefaultCaption = "Change...";
private static readonly string kRemoveDefaultCaption = "Remove...";
private Type _resourceType;
private Lazy<string> _select = new Lazy<string>(() => kSelectDefaultCaption);
private Lazy<string> _change = new Lazy<string>(() => kChangeDefaultCaption);
private Lazy<string> _remove = new Lazy<string>(() => kRemoveDefaultCaption);
public Type ResourceType
{
get { return _resourceType; }
set { _resourceType = value; }
}
public string Select
{
get { return _select.Value; }
set { _select = new Lazy<string>(() => GetResourceText(value, kSelectDefaultCaption)); }
}
public string Change
{
get { return _change.Value; }
set { _change = new Lazy<string>(() => GetResourceText(value, kChangeDefaultCaption)); }
}
public string Remove
{
get { return _remove.Value; }
set { _remove = new Lazy<string>(() => GetResourceText(value, kRemoveDefaultCaption)); }
}
private string GetResourceText(string key, string #default)
{
// initialize to default.
var result = #default;
if (_resourceType != null && !string.IsNullOrEmpty(key))
{
// initialize to the value of the key,
// that could be a user supplied string literal
result = key;
// attempt to retrieve it from the resources.
ResourceManager rm = new ResourceManager(_resourceType);
try
{
result = rm.GetString(key);
}
catch
{
// could not retrieve key, using the key value as the result.
}
}
return result;
}
}
I'm pretty dump. It doesn't creates new instances at all; I answered my question in moment when I asked.
return GetResourceText(m => m.Select, "Select..."); is recursion without end, but return GetResourceText(m => m._select, "Select..."); isn't, because I'm not calling method GetResourceText again.
I'm sorry boys for silly question.
An slight modification to Alex's answer, if you wish to keep your compile-time safety on using the property names:
public class UploadAttribute : Attribute
{
private Type _resourceType;
private Lazy<string> _select;
private Lazy<string> _change;
private Lazy<string> _remove;
UploadAttribute()
{
_select = new Lazy<string>(() => GetResourceText(m => m.Select, "Select..."));
_change = new Lazy<string>(() => GetResourceText(m => m.Change, "Change..."));
_remove = new Lazy<string>(() => GetResourceText(m => m.Remove, "Remove..."));
}
public Type ResourceType
{
get { return _resourceType; }
set { _resourceType = value; }
}
public string Select
{
get { return _select.Value; }
set { _select = new Lazy<string>(() => value); }
}
public string Change
{
get { return _change.Value; }
set { _change = new Lazy<string>(() => value); }
}
public string Remove
{
get { return _remove.Value; }
set { _remove = new Lazy<string>(() => value); }
}
private string GetResourceText(Expression<Func<UploadAttribute, string>> expression, string #default)
{
var result = #default;
var memberExpression = expression.Body as MemberExpression;
if (_resourceType != null && memberExpression != null)
{
ResourceManager rm = new ResourceManager(_resourceType);
try
{
result = rm.GetString(memberExpression.Member.Name);
}
catch
{
// if string wasn't found in resource file than use what user specify; don't by big brother.
}
}
return result;
}
}
The question is rather about serialized generic list<>
I have used a tool xsd2code for generating a serialized class file from xml schema to generate xml file on given data.
The class file contains all the xml data fields variables into classes as bellow-
public partial class Awmds
{
private List bol_segmentField;
public Awmds()
{
this.bol_segmentField = new List<AwmdsBol_segment>();
}
public List<AwmdsBol_segment> Bol_segment
{
get
{
return this.bol_segmentField;
}
set
{
this.bol_segmentField = value;
}
}
}
public partial class AwmdsBol_segment
{
private AwmdsBol_segmentBol_id bol_idField;
private sbyte consolidated_CargoField;
private AwmdsBol_segmentLoad_unload_place load_unload_placeField;
private AwmdsBol_segmentTraders_segment traders_segmentField;
private List<AwmdsBol_segmentCtn_segment> ctn_segmentField;
private AwmdsBol_segmentGoods_segment goods_segmentField;
private string value_segmentField;
public AwmdsBol_segment()
{
this.goods_segmentField = new AwmdsBol_segmentGoods_segment();
this.ctn_segmentField = new List<AwmdsBol_segmentCtn_segment>();
this.traders_segmentField = new AwmdsBol_segmentTraders_segment();
this.load_unload_placeField = new AwmdsBol_segmentLoad_unload_place();
this.bol_idField = new AwmdsBol_segmentBol_id();
}
public AwmdsBol_segmentBol_id Bol_id
{
get
{
return this.bol_idField;
}
set
{
this.bol_idField = value;
}
}
public sbyte Consolidated_Cargo
{
get
{
return this.consolidated_CargoField;
}
set
{
this.consolidated_CargoField = value;
}
}
.... and so on for other fields ....
}
public partial class AwmdsBol_segmentBol_id
{
private string bol_referenceField;
private sbyte line_numberField;
private sbyte bol_natureField;
private string bol_type_codeField;
public string Bol_reference
{
get
{
return this.bol_referenceField;
}
set
{
this.bol_referenceField = value;
}
}
public sbyte Line_number
{
get
{
return this.line_numberField;
}
set
{
this.line_numberField = value;
}
}
public sbyte Bol_nature
{
get
{
return this.bol_natureField;
}
set
{
this.bol_natureField = value;
}
}
public string Bol_type_code
{
get
{
return this.bol_type_codeField;
}
set
{
this.bol_type_codeField = value;
}
}
}
.... and so on for other classes ....
I have all the data to fill the generic list: List bol_segmentField
My problem is I dont know how to insert the data to the members of List bol_segmentField based on the class file.
Someone please help me to fillup the generic list by the class variables.
Maybe I am missing something, but would this work:
var awds = new Awmds();
var segment = new AwmdsBol_segment();
// here fill in the segment
awds.Bol_segment.Add(segment);
I am trying to modify an object after its creation. I would like to set the properties of this object to -1 for int or string.empty "" for a string. Bellow is a sample code of what I already have.
class TestClassAccess{
public int MyPropInt { get; set { ModifyOnAccessDenied<int>(value); } }
public string MyPropString { get; set { ModifyOnAccessDenied<string>(value); } }
public TestClassAccess() { }
private T ModifyOnAccessDenied<T>(T propertyToChange) {
var _hasAccess = false; //not really important how this is made
if (!_hasAccess)
{
if (propertyToChange is string)
propertyToChange = string.Empty;
else if (propertyToChange is int)
propertyToChange = -1;
}
return propertyToChange;
}
}
so.. issues i am having.
It doesn't compile as I cannot convert property to change to string or int.
I don't knot if i can use set methods like this.
Is this possible or am i being to ambitious.
Thank.s
KJ
If you are checking for specific types in a generic function you are probably doing something wrong. In this case you can easily just pass in a default value rather than having it hard coded:
private T ModifyOnAccessDenied<T>(T newValue, T defaultValue) {
var _hasAccess = false; //not really important how this is made
if (!_hasAccess)
{
newValue = defaultValue;
}
return newValue;
}
I've also renamed propertyToChange to newValue because what you have in this function is the new value, not a property.
Also your property definitions will not work. If you need to include any logic in your getter or setting you cannot use the auto-initializer syntax and must implement the property with a backing field.
There doesn't seem to be a point in making this function generic if it needs specific action for each type. This seems more appropriate.
class TestClassAccess
{
public int MyPropInt { get; set { ModifyOnAccessDenied<int>(value); } }
public string MyPropString { get; set { ModifyOnAccessDenied<string>(value); } }
public TestClassAccess() { }
private static volatile bool _hasAccess = false;
private string ModifyOnAccessDenied<string>(string propertyToChange)
{
if (!_hasAccess)
return string.Empty;
return propertyToChange;
}
private int ModifyOnAccessDenied<int>(int propertyToChange)
{
if (!_hasAccess)
return -1;
return propertyToChange;
}
}
You can however do this using dynamics, but this does require .NET 4.0
private T ModifyOnAccessDenied<T>(T propertyToChange)
{
if (!_hasAccess)
{
if (propertyToChange is string)
return (dynamic)string.Empty;
else if (propertyToChange is int)
return (dynamic)(int)-1;
}
return propertyToChange;
}
Fully working sample:
static class Program
{
[STAThread]
static void Main()
{
TestClassAccess test = new TestClassAccess();
test.MyPropInt = 4;
test.MyPropString = "TEST";
Console.WriteLine("MyPropInt {0}, MyPropString '{1}'",test.MyPropInt, test.MyPropString);
// Prints "MyPropInt -1, MyPropString ''
}
class TestClassAccess
{
private int myPropInt = 0;
public int MyPropInt { get { return myPropInt; } set { myPropInt = ModifyOnAccessDenied<int>(value); } }
private string myPropString = string.Empty;
public string MyPropString { get { return myPropString; } set { myPropString = ModifyOnAccessDenied<string>(value); } }
public static volatile bool _hasAccess = false;
private T ModifyOnAccessDenied<T>(T propertyToChange)
{
if (!_hasAccess)
{
if (propertyToChange is string)
return (dynamic)string.Empty;
else if (propertyToChange is int)
return (dynamic)(int)-1;
}
return propertyToChange;
}
}
}
As is well known, CM doesn't support passing a object of complex type through NavigationService like MVVM Light. So I searched for a workaround and did it like this.
There are two viewmodels: MainPageViewModel and SubPageViewModel.
I first defined 3 classes, namely GlobalData, SnapshotCache and StockSnapshot. StockSnapshot is the type of which the object I want to pass between the 2 viewmodels.
public class SnapshotCache : Dictionary<string, StockSnapshot>
{
public StockSnapshot GetFromCache(string key)
{
if (ContainsKey(key))
return this[key];
return null;
}
}
public class GlobalData
{
private GlobalData()
{
}
private static GlobalData _current;
public static GlobalData Current
{
get
{
if (_current == null)
_current = new GlobalData();
return _current;
}
set { _current = value; }
}
private SnapshotCache _cachedStops;
public SnapshotCache Snapshots
{
get
{
if (_cachedStops == null)
_cachedStops = new SnapshotCache();
return _cachedStops;
}
}
}
public class StockSnapshot
{
public string Symbol { get; set; }
public string Message { get; set; }
}
Next, I call the navigation service on MainPageViewModel like this:
StockSnapshot snap = new StockSnapshot {Symbol="1", Message = "The SampleText is here again!" };
GlobalData.Current.Snapshots[snap.Symbol] = snap;
NavigationService.UriFor<SubPageViewModel>().WithParam(p=>p.Symbol,snap.Symbol).Navigate();
And on SubPageViewModel I've got this:
private string _symbol;
public string Symbol
{
get { return _symbol; }
set
{
_symbol = value;
NotifyOfPropertyChange(() => Symbol);
}
}
public StockSnapshot Snapshot
{
get { return GlobalData.Current.Snapshots[Symbol]; }
}
And that's where the problem lies. When I run the program, I find out that it always runs to the getter of Snapshot first, when Symbol hasn't been initialized yet. So later I've tried adding some extra code to eliminate the ArgumentNullException so that it can run to the setter of Symbol and then everything goes fine except that the UI doesn't get updated anyway.
Could anyone tell me where I've got wrong?
Thx in advance!!
Why not just use:
private string _symbol;
public string Symbol
{
get { return _symbol;}
set
{
_symbol = value;
NotifyOfPropertyChange(() => Symbol);
NotifyOfPropertyChange(() => Snapshot);
}
}
public StockSnapshot Snapshot
{
get { return Symbol!=null? GlobalData.Current.Snapshots[Symbol]:null; }
}
In this case you don't try and get the data from GlobalData when Symbol is null (sensible approach anyway!) and when "Symbol" is set you call NotifyOfPropertyChange() on Snapshot to force a re-get of the property.
So I have a property grid that I want to have an object bound to. When the application is running a button will show up and display a form which will allow that object to have its properties set and returned back to the property that called the form.
Here is what I have so far:
I cant get the property to show up in my property grid. Basically I want to use a form to fill in other items in the property grid.
I hope my question was clear enough...
public class OptoSetupFormEditor : UITypeEditor
{
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
{
return UITypeEditorEditStyle.Modal;
}
public override object EditValue(ITypeDescriptorContext context, System.IServiceProvider provider, object value)
{
IWindowsFormsEditorService svc = provider.GetService(typeof(IWindowsFormsEditorService)) as IWindowsFormsEditorService;
DataTemp opto = value as DataTemp;
if (svc != null && opto != null)
{
using (OptoSigmaSetup form = new OptoSigmaSetup())
{
if (svc.ShowDialog(form) == DialogResult.OK)
{
opto.Direction = form.Direction;
opto.FunctionToCall = form.FunctionToCall;
opto.Duration = form.Duration;
// OptoSigmaTest.Command = form.
}
}
}
return opto; // can also replace the wrapper object here
}
}
[Editor(typeof(OptoSetupFormEditor),typeof(UITypeEditor))]
[TypeConverter(typeof(ExpandableObjectConverter))]
public DataTemp Test1
{
set
{
this.Duration = value.Duration ;
this.Direction = value.Direction;
this.FunctionUsed = value.FunctionToCall;
}
}
[ReadOnly(true), Category("Setup")]
public string FunctionUsed
{
get { return functionUsed; }
set { functionUsed = value; }
}
[ReadOnly(true), Category("Setup")]
public int Duration
{
get { return duration; }
set { duration = value; }
}
[ReadOnly(true),Category("Setup")]
public string Direction
{
get { return direction; }
set { direction = value; }
}
public class DataTemp
{
private int duration = 0;
private string direction = "Positive";
private string functionToCall = "Home";
public string FunctionToCall
{
get { return functionToCall; }
set { functionToCall = value; }
}
public int Duration
{
get { return duration; }
set { duration = value; }
}
public string Direction
{
get { return direction; }
set { direction = value; }
}
}
Thanks in advance. If it needs more clarification, please let me know
Have you tried augmenting the properties you wish to display with the Browsable attribute?
[Browsable(true)]
[ReadOnly(true), Category("Setup")]
public string FunctionUsed
{
get { return functionUsed; }
set { functionUsed = value; }
}
MSDN: BrowsableAttribute
EDIT:
Hm, according to MSDN, properties without this attribute, or those which have the attribute specified with a value of true, should display in Property windows; so this is a suggestion left wanting.