i was reading a tutorial for windows phone 7 using C# and sliverlight and i found this line
public static class Settings
{
public static readonly Setting<bool> IsRightHanded =
new Setting<bool>("IsRightHanded", true);
public static readonly Setting<double> Threshold =
new Setting<double>("Threshold", 1.5);
}
i can't find the Setting Class in C# i wanted to know if it's under a special namespace or need an additional reference to add
If it is a custom class, and not described in the tutorial you got this from, can you not reimplement it? It looks to me like the class would have a signature something like this:
public class Setting<T>
{
public Setting<T>(string name, T value)
{
Name = name;
Value = value;
}
public string Name { get; set; }
public T Value { get; set; }
}
Of course, there could be more to it than that. What properties are being accessed / bound to on this class in the tutorial?
If you are using "101 Windows Phone 7 Apps" book, Setting class is implemented and explained in Chapter 20.
Here's the Setting<T> class that I use. It supports change notification via INotifyPropertyChanged which is useful for binding (in WPF/SL/etc). It also maintains a copy of the default value so that it may be reset if required.
As a general rule, T should be immutable.
public class Setting<T> : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public event Action<T> Changed;
private readonly T _defaultValue;
private T _value;
public Setting(T defaultValue)
{
_defaultValue = defaultValue;
_value = defaultValue;
}
public T Value
{
get { return _value; }
set
{
if (Equals(_value, value))
return;
_value = value;
var evt = Changed;
if (evt != null)
evt(value);
var evt2 = PropertyChanged;
if (evt2 != null)
evt2(this, new PropertyChangedEventArgs("Value"));
}
}
public void ResetToDefault()
{
Value = _defaultValue;
}
}
Related
The main purpose is to show intellisense when setting the property. It would be great if I could do it via an attribute like the image below.
The property should remain a string(not enum or struct) so that Mongo's BsonSerializer can serialize it properly. Here is an example of what it might look like:
To help other developers on the team know possible (but not exlusive) values they can use for the Type field Code Completion should display values that can be used as shown below:
(Edited) I was able to solve this by creating my own type
public class SkinType:StringType<SkinType>
{
public SkinType(string value)
{
Value = value;
}
public SkinType()
{
}
public static implicit operator string(SkinType d)
{
return d.Value;
}
public static implicit operator SkinType(string d)
{
return new SkinType(d);
}
public const string StringValue = nameof(StringValue);
public const string Color = nameof(Color);
}
Now I get intellisense for my Type property and Mongo knows how to serialize it.
Here is how I use it:
public class Skin : ServiceMongoIdentity
{
//removed some properties for brevity.
[BsonIgnoreIfDefault]
[BsonDefaultValue(SkinType.StringValue)]
public SkinType Type { get; set; } = SkinType.StringValue;
}
Here is how the StringType base class is defined. I had to make Value public because Generics cannot have constructors with parameters
public abstract class StringType<T> where T :StringType<T>,new()
{
[ReadOnly(true)]
public string Value;
public T FromString(string d)
{
return new T
{
Value = d
};
}
public override bool Equals(object obj)
{
return obj?.ToString() == Value;
}
public override int GetHashCode()
{
return Value.GetHashCode();
}
public override string ToString()
{
return Value;
}
}
In C#, I have a suffiently complex Model. I already have a WPF Client to manipulate that model. I'm using MVVM. All objects in that model support INotifyPropertyChanged and all properties that are collections support INotifyCollectionChanged.
Take this as a simplied example:
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace CollectionTest1
{
public class PropertyChangedSupport : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void FirePropertyChange([System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public class Company : PropertyChangedSupport
{
private string name;
public String Name { get { return name; } set { name = value; FirePropertyChange(); } }
public ObservableCollection<Employee> Employees { get; } = new ObservableCollection<Employee>();
}
public class Employee : PropertyChangedSupport
{
private string name;
public String Name { get { return name; } set { name = value; FirePropertyChange(); } }
public ObservableCollection<PresentTimespan> PresentTimespans { get; } = new ObservableCollection<PresentTimespan>();
public Boolean IsPresentAt(DateTime t)
{
foreach (PresentTimespan pt in PresentTimespans)
{
if (pt.Start.CompareTo(t) <= 0 && pt.Finish.CompareTo(t) >= 0) return true;
}
return false;
}
}
public class PresentTimespan : PropertyChangedSupport
{
private string comment;
public String Comment { get { return comment; } set { comment = value; FirePropertyChange(); } }
private DateTime start;
public DateTime Start { get { return start; } set { start = value; FirePropertyChange(); } }
private DateTime finish;
public DateTime Finish { get { return finish; } set { finish = value; FirePropertyChange(); } }
}
public class CompanyStatusView : PropertyChangedSupport
{
private DateTime currentTime;
public DateTime CurrentTime { get { return currentTime; } set { currentTime = value; FirePropertyChange(); } }
private Company currentCompany;
public Company CurrentCompany { get { return currentCompany; } set { currentCompany = value; FirePropertyChange(); } }
public ObservableCollection<Employee> PresentEmployees { get; } = new ObservableCollection<Employee>();
public CompanyStatusView()
{
UpdatePresentEmployees();
}
private void UpdatePresentEmployees()
{
PresentEmployees.Clear();
foreach (Employee e in CurrentCompany.Employees) {
if (e.IsPresentAt(currentTime)) PresentEmployees.Add(e);
}
}
}
}
I'd like to have UpdatePresentEmployees called whenever there are changes in:
Collection Company.Employees.PresentTimespans
Property Company.Employees.PresentTimespans.Start
Property Company.Employees.PresentTimespans.Finish
Collection Company.Employees
Property CurrentTime
Property CurrentCompany
So it's basically any property or collection read by UpdatePresentEmployees.
My best solution so far included registering a lot of event handlers to all the objects mentioned above. That included to have a couple of Dictionary instances to track which added objects I have to subscribe to and especially which I have to unsubscribe from.
The most difficult and annoying part was to subscribe to all the PresentTimespan objects to listen for property changes and all the PresentTimespans collections of Employee to listen for collection changes.
My guess is that there has to be a better way to do this.
After all, in JFace (Java) there is a very interesting solution that uses ObservableTracker. So there you'd only provide the code for UpdatePresentEmployees and ObservableTracker tracks which objects have been read and automatically makes you listen for changes in any of these and also correctly unsubscribes from irrelevant objects. So there are better approaches to this problem in general. What is C# offering? Can it do better than my best solution I mentioned above? Can I avoid some of the boilerplate code? Can it be done with .net provided classes or do I need some additional classes/libraries?
Thanks for your kind help and advice in advance!
You could use BindingList instead of ObservableCollection and attach to the the ListChanged Event. But keep in mind that BindingList has some disadvantages like not being very fast. For further information this could be interesting: difference between ObservableCollection and BindingList
If you dont wanna use BindingList you have to wire your items with events.
As pointed out by Nikhil Agrawal, Rx or ReactiveUI is a good framework for my purpose. So I consider that to be a solution.
Is there a way to use PostSharp to change this kind of code:
private _property;
public Object Property
{
get { return _property; }
set
{
if (_property != value)
{
_property = value;
PropertyChanged("Property");
}
}
}
into something like:
[NotifyChanged]
public Object Property { get; set; }
?
There are good instructions here:
http://www.postsharp.net/aspects/examples/inotifypropertychanged
This seems to match up with what you're looking for.
is there a way to make an enum value not browsable to combo box
or just, not to come back from Enum.GetValues() ??
public enum DomainTypes
{
[Browsable(true)]
Client = 1,
[Browsable(false)]
SecretClient = 2,
}
This is a generic method (based on another SO answer which I can't find) which you can call on any enum.
By the way, the Browsable attribute is already defined in System.ComponentModel.
For example:
ComboBox.DataSource = EnumList.Of<DomainTypes>();
...
public class EnumList
{
public static List<T> Of<T>()
{
return Enum.GetValues(typeof(T))
.Cast<T>()
.Where(x =>
{
BrowsableAttribute attribute = typeof(T)
.GetField(Enum.GetName(typeof(T), x))
.GetCustomAttributes(typeof(BrowsableAttribute),false)
.FirstOrDefault() as BrowsableAttribute;
return attribute == null || attribute.Browsable == true;
}
)
.ToList();
}
}
There is nothing already in place to do this for you with the Enum.GetValues() method. If you want to use attributes, you can create your own custom attribute and use it via reflection:
public class BrowsableAttribute : Attribute
{
public bool IsBrowsable { get; protected set; }
public BrowsableAttribute(bool isBrowsable)
{
this.IsBrowsable = isBrowsable;
}
}
public enum DomainTypes
{
[Browsable(true)]
Client = 1,
[Browsable(false)]
SecretClient = 2,
}
And then you can use reflection to check for custom attributes and generate a list of Enums based on the Browsable attribute.
It really can't be done in C# - a public enumeration exposes all members. Instead, consider using a wrapper class to hide/expose the items selectively. Maybe something like this:
public sealed class EnumWrapper
{
private int _value;
private string _name;
private EnumWrapper(int value, string name)
{
_value = value;
_name = name;
}
public override string ToString()
{
return _name;
}
// Allow visibility to only the items you want to
public static EnumWrapper Client = new EnumWrapper(0, "Client");
public static EnumWrapper AnotherClient= new EnumWrapper(1, "AnotherClient");
// The internal keyword makes it only visible internally
internal static readonly EnumWrapper SecretClient= new EnumWrapper(-1, "SecretClient");
}
Hope this helps. Good luck!
If my understanding of the internal workings of this line is correct:
public int MyInt { get; set; }
Then it behind the scenes does this:
private int _MyInt { get; set; }
Public int MyInt {
get{return _MyInt;}
set{_MyInt = value;}
}
What I really need is:
private bool IsDirty { get; set; }
private int _MyInt { get; set; }
Public int MyInt {
get{return _MyInt;}
set{_MyInt = value; IsDirty = true;}
}
But I would like to write it something like:
private bool IsDirty { get; set; }
public int MyInt { get; set{this = value; IsDirty = true;} }
Which does not work. The thing is some of the objects I need to do the IsDirty on have dozens of properties and I'm hoping there is a way to use the auto getter/setter but still set IsDirty when the field is modified.
Is this possible or do I just have to resign myself to tripling the amount of code in my classes?
You'll need to handle this yourself:
private bool IsDirty { get; set; }
private int _myInt; // Doesn't need to be a property
Public int MyInt {
get{return _myInt;}
set{_myInt = value; IsDirty = true;}
}
There is no syntax available which adds custom logic to a setter while still using the automatic property mechanism. You'll need to write this with your own backing field.
This is a common issue - for example, when implementing INotifyPropertyChanged.
Create an IsDirty decorator (design pattern) to wrap some your properties requiring the isDirty flag functionality.
public class IsDirtyDecorator<T>
{
public bool IsDirty { get; private set; }
private T _myValue;
public T Value
{
get { return _myValue; }
set { _myValue = value; IsDirty = true; }
}
}
public class MyClass
{
private IsDirtyDecorator<int> MyInt = new IsDirtyDecorator<int>();
private IsDirtyDecorator<string> MyString = new IsDirtyDecorator<string>();
public MyClass()
{
MyInt.Value = 123;
MyString.Value = "Hello";
Console.WriteLine(MyInt.Value);
Console.WriteLine(MyInt.IsDirty);
Console.WriteLine(MyString.Value);
Console.WriteLine(MyString.IsDirty);
}
}
You can make it simple or complex. It depends on how much work you want to invest. You can use aspect oriented programming to add the aspect via an IL weaver into the IL code with e.g. PostSharp.
Or you can create a simple class that does handle the state for your property. It is so simple that the former approach only pays off if you have really many properties to handle this way.
using System;
class Dirty<T>
{
T _Value;
bool _IsDirty;
public T Value
{
get { return _Value; }
set
{
_IsDirty = true;
_Value = value;
}
}
public bool IsDirty
{
get { return _IsDirty; }
}
public Dirty(T initValue)
{
_Value = initValue;
}
}
class Program
{
static Dirty<int> _Integer;
static int Integer
{
get { return _Integer.Value; }
set { _Integer.Value = value; }
}
static void Main(string[] args)
{
_Integer = new Dirty<int>(10);
Console.WriteLine("Dirty: {0}, value: {1}", _Integer.IsDirty, Integer);
Integer = 15;
Console.WriteLine("Dirty: {0}, value: {1}", _Integer.IsDirty, Integer);
}
}
Another possibility is to use a proxy class which is generated at runtime which does add the aspect for you. With .NET 4 there is a class that does handle this aspect already for you. It is called ExpandObject which does notify you via an event when a property changes. The nice things is that ExpandoObject allows you to define at runtime any amount of properties and you get notifications about every change of a property. Databinding with WPF is very easy with this type.
dynamic _DynInteger = new ExpandoObject();
_DynInteger.Integer = 10;
((INotifyPropertyChanged)_DynInteger).PropertyChanged += (o, e) =>
{
Console.WriteLine("Property {0} changed", e.PropertyName);
};
Console.WriteLine("value: {0}", _DynInteger.Integer );
_DynInteger.Integer = 20;
Console.WriteLine("value: {0}", _DynInteger.Integer);
Yours,
Alois Kraus
I'm going to add on to Simon Hughes' answer. I propose the same thing, but add a way to allow the decorator class to update a global IsDirty flag automatically. You may find it to be less complex to do it the old-fashioned way, but it depends on how many properties you're exposing and how many classes will require the same functionality.
public class IsDirtyDecorator<T>
{
private T _myValue;
private Action<bool> _changedAction;
public IsDirtyDecorator<T>(Action<bool> changedAction = null)
{
_changedAction = changedAction;
}
public bool IsDirty { get; private set; }
public T Value
{
get { return _myValue; }
set
{
_myValue = value;
IsDirty = true;
if(_changedAction != null)
_changedAction(IsDirty);
}
}
}
Now you can have your decorator class automatically update some other IsDirty property in another class:
class MyObject
{
private IsDirtyDecorator<int> _myInt = new IsDirtyDecorator<int>(onValueChanged);
private IsDirtyDecorator<int> _myOtherInt = new IsDirtyDecorator<int>(onValueChanged);
public bool IsDirty { get; private set; }
public int MyInt
{
get { return _myInt.Value; }
set { _myInt.Value = value; }
}
public int MyOtherInt
{
get { return _myOtherInt.Value; }
set { _myOtherInt.Value = value; }
}
private void onValueChanged(bool dirty)
{
IsDirty = true;
}
}
I have created a custom Property<T> class to do common operations like that. I haven't used it thoroughly yet though, but it could be used in this scenario.
Code can be found here: http://pastebin.com/RWTWNNCU
You could use it as follows:
readonly Property<int> _myInt = new Property<int>();
public int MyInt
{
get { return _myInt.GetValue(); }
set { _myInt.SetValue( value, SetterCallbackOption.OnNewValue, SetDirty ); }
}
private void SetDirty( int oldValue, int newValue )
{
IsDirty = true;
}
The Property class handles only calling the passed delegate when a new value is passed thanks to the SetterCallbackOption parameter. This is default so it can be dropped.
UPDATE:
This won't work apparently when you need to support multiple types (besides int), because the delegate won't match then. You could ofcourse always adjust the code to suit your needs.