How to wrap Model Property in ViewModel Property - c#

Instead of directly exposing entire Model to the View, I want to have ViewModel properties which are just proxies for each Model properties. For example;
private Product _product;
public string ProductName
{
get { return _product.ProductName; }
set
{
SetProperty(ref _product.ProductName, value);
}
}
But the above example causes the error of A property, indexer or dynamic member access may not be passed as an out or ref parameter.
How should I solve this problem?
P.S. My Models are not implemented by INPC interface. They are just simple POCO classes.

What you want is a façade or decorator object that will act as your model in your VM, not wrapping every model property with ViewModel properties. This allows you to not only reuse your models (facades/decorators), but it also keeps the concerns where they belong. You define your properties just like chipples provided, but call OnPropertyChanged() in the setter. You can't use the SetProperty method when wrapping other properties.
Something similar to this:
class Person
{
public string Name { get; set; }
}
class PersonFacade : BindableBase
{
Person _person;
public string Name
{
get { return _person.Name; }
set
{
_person.Name = value;
OnPropertyChanged();
}
}
}
class ViewModel : BindableBase
{
private PersonFacade _person;
public PersonFacade Person
{
get { return _person; }
set { SetProperty(ref _person, value); }
}
}

Maybe this is an old thread but C# MVVM property makes me stressed. Imagine You need to write 200 properties a day.
I have another approach to creating BaseClass.
public abstract class NotifyPropertiesBase : INotifyPropertyChanged, INotifyPropertyChanging
{
public event PropertyChangingEventHandler PropertyChanging;
public event PropertyChangedEventHandler PropertyChanged;
readonly Dictionary<string, object> _propertyStore = new Dictionary<string, object>();
public PropertyChangingEventArgs NotifyChanging([CallerMemberName] string propertyName = null)
{
var arg = new PropertyChangingEventArgs(propertyName);
PropertyChanging?.Invoke(this, arg);
return arg;
}
public PropertyChangedEventArgs NotifyChanged([CallerMemberName] string propertyName = null)
{
var arg = new PropertyChangedEventArgs(propertyName);
PropertyChanged?.Invoke(this, arg);
return arg;
}
public void SetPropValue(object newValue, [CallerMemberName] string propertyName = null)
{
if (GetType().GetMember(propertyName).Count() != 1)
throw new NotSupportedException($"\"{propertyName}\" Not Supported or maybe its not a Property");
var member = GetType().GetMember(propertyName).FirstOrDefault();
if (member.MemberType != System.Reflection.MemberTypes.Property)
throw new NotSupportedException($"Not Support Member Type {member.MemberType}");
var pInfo = member.DeclaringType.GetProperties().First();
NotifyChanging(propertyName);
if (!_propertyStore.ContainsKey(propertyName))
_propertyStore.Add(propertyName, newValue);
else
_propertyStore[propertyName] = newValue;
NotifyChanged(propertyName);
}
public T GetPropertyValue<T>([CallerMemberName] string propertyName = null)
{
return (T)GetPropertyValue(propertyName);
}
public object GetPropertyValue([CallerMemberName] string propertyName = null)
{
if (GetType().GetMember(propertyName).Count() != 1)
throw new NotSupportedException($"\"{propertyName}\" Not Supported or maybe its not a Property");
var member = GetType().GetMember(propertyName).FirstOrDefault();
if (member.MemberType != System.Reflection.MemberTypes.Property)
throw new NotSupportedException($"Not Support Member Type {member.MemberType}");
var pInfo = member.DeclaringType.GetProperties().First();
if (!_propertyStore.ContainsKey(propertyName))
{
_propertyStore.Add(propertyName, GetDefault(pInfo.PropertyType));
}
return _propertyStore[propertyName];
}
object GetDefault(Type t)
{
if (t.IsValueType)
{
return Activator.CreateInstance(t);
}
return null;
}
}
Class Usages:
class Program
{
static void Main(string[] args)
{
var t = new Test();
t.PropertyChanged += T_PropertyChanged;
t.ValueTest = "Hello World!";
var data = t.GetPropertyValue(nameof(t.ValueTest));
Console.Write(data);
}
private static void T_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
Console.WriteLine(e.PropertyName);
}
}
public class Test : NotifyPropertiesBase
{
public string ValueTest
{
get => GetPropertyValue<string>();
set => SetPropValue(value);
}
}

It is simple make with helper class like ViewModelBase, which simplifies raise PropertyChanged event:
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged = delegate { };
protected void OnPropertyChanged<T>(Expression<Func<T>> propertyExpression)
{
PropertyChanged(this, new PropertyChangedEventArgs(ExtractPropertyName(propertyExpression)));
}
private static string ExtractPropertyName<T>(Expression<Func<T>> propertyExpression)
{
if (propertyExpression == null)
throw new ArgumentNullException("propertyExpression");
var memberExpression = propertyExpression.Body as MemberExpression;
if (memberExpression == null)
throw new ArgumentException("memberExpression");
var property = memberExpression.Member as PropertyInfo;
if (property == null)
throw new ArgumentException("property");
var getMethod = property.GetGetMethod(true);
if (getMethod.IsStatic)
throw new ArgumentException("static method");
return memberExpression.Member.Name;
}
}
then, simple POCO class Person:
class Person
{
public string Name { get; set; }
public double Age { get; set; }
}
we can wrap to ViewModel like:
public class PersonViewModel : ViewModelBase
{
private readonly Person person = new Person();
public string Name
{
get { return person.Name; }
set
{
person.Name = value;
OnPropertyChanged(() => Name);
}
}
public double Age
{
get { return person.Age; }
set
{
person.Age = value;
OnPropertyChanged(() => Age);
}
}
}

SetProperty is not needed here, you can just do this:
private Product _product;
public string ProductName
{
get { return _product.ProductName; }
set
{
_product.ProductName = value;
}
}

Related

How to copy custom ObservableCollection elements to another custom ObservableCollection?

I created a MTObservableCollection class that derives from ObservableCollection for multithreading. This is how the function looks like:
public class MTObservableCollection<T> : ObservableCollection<T> where T: LogClassa
{
public MTObservableCollection() { }
public override event NotifyCollectionChangedEventHandler CollectionChanged;
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
NotifyCollectionChangedEventHandler CollectionChanged = this.CollectionChanged;
if (CollectionChanged != null)
foreach (NotifyCollectionChangedEventHandler nh in CollectionChanged.GetInvocationList())
{
DispatcherObject dispObj = nh.Target as DispatcherObject;
if (dispObj != null)
{
Dispatcher dispatcher = dispObj.Dispatcher;
if (dispatcher != null && !dispatcher.CheckAccess())
{
dispatcher.BeginInvoke(
(Action)(() => nh.Invoke(this,
new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset))),
DispatcherPriority.DataBind);
continue;
}
}
nh.Invoke(this, e);
}
}
}
And here is my LogClass
public class LogClass : INotifyPropertyChanged
{
private string timestamp;
private string title;
private string message;
private MTObservableCollection<LogClass> childRowLog = new MTObservableCollection<LogClass>();
public string TimeStamp
{
get { return timestamp; }
set
{
if( timestamp != value )
{
timestamp = value;
OnPropertyChanged("TimeStamp");
}
}
}
public string Title
{
get { return title; }
set
{
if( title!= value )
{
title= value;
OnPropertyChanged("Title");
}
}
}
public string Message
{
get { return message; }
set
{
if( message!= value )
{
message= value;
OnPropertyChanged("Message");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
So if I have two MTObservableCollection collections and I add elements to one of them such as:
public static MTObservableCollection<LogClass> parentLogCollection = new MTObservableCollection<LogClass>();
public MTObservableCollection<LogClass> childLogCollection = new MTObservableCollection<LogClass>();
childLogClass.Add( new LogClass { TimeStamp = "time", Title = "title", Message = "message" } );
Now if I want to add childLogCollection to parentLogCollection, I would do this:
parentLogCollection = new MTObservableCollection<LogClass>(childLogCollection);
I would think I need to create an implementation within the MBObservationCollection class which should be
public MTObservableCollection(MTObservableCollection<T> collection)
{
}
I just don't know what to input into it, how would I perform it?
Try changing the parent of your MTObservableCollection like this:
public MTObservableCollection(MTObservableCollection<T> collection) : base(collection)
{
}

INotifyPropertyChanged wrapper

I found some solution of INotifyPropertyChanged wrapper but it doesnot do anything. What I am doing wrong? Name updating asynchronous but value in windows do not change. Why?* *
namespace WpfApplication1.ViewModel
{
class CustomerViewModel : INotifyPropertyChanged, IWeakEventListener
{
private readonly Customer _customer;
internal CustomerViewModel(Customer customer)
{
if (customer == null)
{
throw new ArgumentNullException("personModel");
}
_customer = customer;
NotifyPropertyChangedEventManager.AddListener(_customer, this);
Action Start = new Action(UpdateAsync);
IAsyncResult result = Start.BeginInvoke(null, null);
}
private void UpdateAsync()
{
int i = 0;
while (true)
{
System.Threading.Thread.Sleep(1000);
_customer.Name = (++i).ToString();
}
}
public string Name
{
get { return _customer.Name; }
set { _customer.Name = value; }
}
public string JobTitle
{
get { return _customer.Work; }
set { _customer.Work = value; }
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
#region IWeakEventListener Members
public bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
{
PropertyChangedEventArgs pcArgs = e as PropertyChangedEventArgs;
if (pcArgs != null)
{
OnPropertyChanged(pcArgs.PropertyName);
return true;
}
return false;
}
#endregion
}
public class NotifyPropertyChangedEventManager : WeakEventManager
{
public static NotifyPropertyChangedEventManager CurrentManager
{
get
{
var manager_type = typeof(NotifyPropertyChangedEventManager);
var manager = WeakEventManager.GetCurrentManager(manager_type) as NotifyPropertyChangedEventManager;
if (manager == null)
{
manager = new NotifyPropertyChangedEventManager();
WeakEventManager.SetCurrentManager(manager_type, manager);
}
return manager;
}
}
public static void AddListener(INotifyPropertyChanged source, IWeakEventListener listener)
{
CurrentManager.ProtectedAddListener(source, listener);
return;
}
public static void RemoveListener(INotifyPropertyChanged source, IWeakEventListener listener)
{
CurrentManager.ProtectedRemoveListener(source, listener);
return;
}
protected override void StartListening(object source)
{
((INotifyPropertyChanged)source).PropertyChanged += Source_PropertyChanged; return;
}
protected override void StopListening(object source)
{
((INotifyPropertyChanged)source).PropertyChanged -= Source_PropertyChanged;
return;
}
void Source_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
{ CurrentManager.DeliverEvent(sender, e); };
}
}
}
Customer
public class Customer:INotifyPropertyChanged
{
public string Name { get; set; }
public string Number { get; set; }
public string Work { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
And Xaml code
<Grid>
<Label Content="{Binding Name}"></Label>
</Grid>
Instead of doing the PropertyChanged yourself, you can also use Fody.PropertyChanged. (https://github.com/Fody/PropertyChanged)
You can install it via Nuget in Visual Studio.
What is does it automaticly adds the PropertyChanged implementation when compiling.
Your code:
using PropertyChanged;
[ImplementPropertyChanged]
public class Person
{
public string GivenNames { get; set; }
public string FamilyName { get; set; }
public string FullName
{
get
{
return string.Format("{0} {1}", GivenNames, FamilyName);
}
}
}
What gets compiled:
public class Person : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
string givenNames;
public string GivenNames
{
get { return givenNames; }
set
{
if (value != givenNames)
{
givenNames = value;
OnPropertyChanged("GivenNames");
OnPropertyChanged("FullName");
}
}
}
string familyName;
public string FamilyName
{
get { return familyName; }
set
{
if (value != familyName)
{
familyName = value;
OnPropertyChanged("FamilyName");
OnPropertyChanged("FullName");
}
}
}
public string FullName
{
get
{
return string.Format("{0} {1}", GivenNames, FamilyName);
}
}
public virtual void OnPropertyChanged(string propertyName)
{
var propertyChanged = PropertyChanged;
if (propertyChanged != null)
{
propertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
There are also other features, please read them at the wiki: https://github.com/Fody/PropertyChanged/wiki
I know this question is old and doesn't exactly answer your question. I thought this would be a better solution for you.
Bindable uses a dictionary as a property store. It's easy enough to add the necessary overloads for a subclass to manage its own backing field using ref parameters.
No magic string
No reflection
Can be improved to suppress the default dictionary lookup
The code:
public class Bindable : INotifyPropertyChanged
{
private Dictionary<string, object> _properties = new Dictionary<string, object>();
/// <summary>
/// Gets the value of a property
        /// <typeparam name="T"></typeparam>
/// <param name="name"></param>
/// <returns></returns>
protected T Get<T>([CallerMemberName] string name = null)
{
object value = null;
if (_properties.TryGetValue(name, out value))
return value == null ? default(T) : (T)value;
return default(T);
}
/// <summary>
/// Sets the value of a property
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
/// <param name="name"></param>
protected void Set<T>(T value, [CallerMemberName] string name = null)
{
if (Equals(value, Get<T>(name)))
return;
_properties[name] = value;
OnPropertyChanged(name);
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
used like this
public class Item : Bindable
{
public Guid Id { get { return Get<Guid>(); } set { Set<Guid>(value); } }
}
You have to invoke OnPropertyChanged("Name");
the best place is on the Name poperty setter.
Very convenient way to implement INotifyPropertyChanged is to implement a following method in your class:
protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(storage, value))
return false;
storage = value;
this.OnPropertyChanged(propertyName);
return true;
}
Then you use it like this:
private string _foo;
public string Foo
{
get { return this._foo; }
set { SetProperty(ref this._foo, value); }
}
However, because you are making a wrapper to other class, you can't use references to properties in your CustomerViewModel class. This can be worked around, but it will lead to writing a massive amount of code just to properly implement INotifyPropertyChanged.
Instead of wrapping your Customer class into some other, make it a public property instead:
private Customer _customer;
public Customer Customer
{
get { return this._customer; }
private set { SetProperty(ref this._customer, value); }
}
And in your XAML:
<Grid>
<Label Content="{Binding Customer.Name}"></Label>
</Grid>
Hope this helps.
Aside from the great answers above, you can probably achieve this behavior with a DynamicObject wrapper, wrapping the accessed class, and changing its properties on behalf, triggering a property changed event.
I haven't tried it yet (I'd probably go for Fody), but something like this pseudo might work:
public class InpcWrapperViewModel<T> : DynamicObject, INotifyPropertyChanged
{
public T Original { get; }
public InpcWrapperViewModel(T original)
{
Original = original;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
//set property of Original with reflection etc.
//raise property changed
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
//set with reflection etc.
return true;
}
}
Usage:
dynamic x = new InpcWrapperViewModel<TEntity>(entity);
window.DataContext = x;
x.FirstName = "Hello"; //triggers INPC
If you're using Prism or any other DI etc. you can create a ViewModel factory that wraps the items automatically.
Again, the above is pseudo code never tested or tried.

Mvvm binding with Locator to JumpList LongList

Ok, let's see...
I have this ViewModel Class, it has a builder to retrieve data from storage, another method who asks data to Internet, it has a saver the notifypropertychange methods and the locator methods.
But the problem is how can I Bind it to a jumplistbox, since as I'm using Locator Binding I can't process it as a group to take the headers and order it.
public class FriendLocator
{
private Lazy<ViewModelFriends> mainVMFriends;
public FriendLocator()
{
mainVMFriends = new Lazy<ViewModelFriends>(() => new ViewModelFriends());
}
public ViewModelFriends MainVMFriends
{
get
{
return mainVMFriends.Value;
}
}
}
public class VMFriendsBase : INotifyPropertyChanged
{
public VMFriendsBase()
{ }
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class ViewModelFriends : VMFriendsBase
{
IsolatedStorageSettings settings = IsolatedStorageSettings.ApplicationSettings;
private ObservableCollection<User_friend> Friends;
public ObservableCollection<User_friend> friends
{
get
{
return Friends;
}
set
{
Friends = value;
RaisePropertyChanged("friends");
}
}
public ViewModelFriends()
{
ObservableCollection<User_friend> a = new ObservableCollection<User_friend>();
if (settings.Contains("userFriends"))
{
string listado = settings["userFriends"] as string;
var listajson = JsonConvert.DeserializeObject<objetoslistas.getmyfriends>(listado);
if (listajson.profile != null)
{
foreach (objetoslistas.User user in listajson.profile)
{
User_friend usuario = new User_friend(user);
a.Add(usuario);
}
}
}
friends = a;
AskFriends();
}
public async void AskFriends()
{
ObservableCollection<User_friend> a = new ObservableCollection<User_friend>();
Uri url = new Uri(link);
objetoslistas.GetByUserID paquete = new objetoslistas.GetByUserID();
string respuesta = await metodosJson.jsonPOST(url, paquete);
var respuestajson = JsonConvert.DeserializeObject<objetoslistas.getmyfriends>(respuesta.ToString());
if (respuestajson.error == "")
{
saveFriends(respuesta);
if (respuestajson.profile != null)
{
foreach (objetoslistas.User user in respuestajson.profile)
{
User_friend usuario = new User_friend(user);
a.Add(usuario);
}
}
}
friends = a;
}
public void saveFriends(string jsonfriends)
{
if (!settings.Contains("userFriends"))
settings.Add("userFriends", jsonfriends);
else
settings["userFriends"] = jsonfriends;
settings.Save();
}
}
The methods I use to process data to listbox are
public static List<Group<T>> GetItemGroups<T>(IEnumerable<T> itemList, Func<T, string> getKeyFunc)
{
IEnumerable<Group<T>> groupList = from item in itemList
group item by getKeyFunc(item) into g
orderby g.Key
select new Group<T>(g.Key, g);
return groupList.ToList();
}
public class Group<T> : List<T>
{
public Group(string name, IEnumerable<T> items)
: base(items)
{
this.Title = name;
}
public string Title
{
get;
set;
}
}
Thanks to all
Ok, I finaly solved by myself, I made a conversor like this:
public class ObservableToGroupedConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
var group = (value as ViewModelFriends).friends;
return metodosAuxiliares.GetItemGroups(group.OrderBy(o => o.distraw).ToList(), c => c.online);
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
I added the conversor to the resources and the binding is:
<view:ViewFriends x:Name="vistaAmigos"
DataContext="{Binding MainVMFriends,
Source={StaticResource friendLocator},
Converter={StaticResource friendConvert}}"/>

Custom validation attribute that compares the value of my property with another property's value in my model class

I want to create a custom validation attribute, in which I want to compare the value of my property with another property's value in my model class.
For example I have in my model class:
...
public string SourceCity { get; set; }
public string DestinationCity { get; set; }
And I want to create a custom attribute to use it like this:
[Custom("SourceCity", ErrorMessage = "the source and destination should not be equal")]
public string DestinationCity { get; set; }
//this wil lcompare SourceCity with DestinationCity
How can I get there?
Here's how you could obtain the other property value:
public class CustomAttribute : ValidationAttribute
{
private readonly string _other;
public CustomAttribute(string other)
{
_other = other;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var property = validationContext.ObjectType.GetProperty(_other);
if (property == null)
{
return new ValidationResult(
string.Format("Unknown property: {0}", _other)
);
}
var otherValue = property.GetValue(validationContext.ObjectInstance, null);
// at this stage you have "value" and "otherValue" pointing
// to the value of the property on which this attribute
// is applied and the value of the other property respectively
// => you could do some checks
if (!object.Equals(value, otherValue))
{
// here we are verifying whether the 2 values are equal
// but you could do any custom validation you like
return new ValidationResult(this.FormatErrorMessage(validationContext.DisplayName));
}
return null;
}
}
Please look below for my example:
Model class implements INotifyPropertyChanged
public class ModelClass : INotifyPropertyChanged
{
private string destinationCity;
public string SourceCity { get; set; }
public ModelClass()
{
PropertyChanged += CustomAttribute.ThrowIfNotEquals;
}
[Custom("SourceCity", ErrorMessage = "the source and destination should not be equal")]
public string DestinationCity
{
get
{
return this.destinationCity;
}
set
{
if (value != this.destinationCity)
{
this.destinationCity = value;
NotifyPropertyChanged("DestinationCity");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
Attribute class also contains event hendler.
internal sealed class CustomAttribute : Attribute
{
public CustomAttribute(string propertyName)
{
PropertyName = propertyName;
}
public string PropertyName { get; set; }
public string ErrorMessage { get; set; }
public static void ThrowIfNotEquals(object obj, PropertyChangedEventArgs eventArgs)
{
Type type = obj.GetType();
var changedProperty = type.GetProperty(eventArgs.PropertyName);
var attribute = (CustomAttribute)changedProperty
.GetCustomAttributes(typeof(CustomAttribute), false)
.FirstOrDefault();
var valueToCompare = type.GetProperty(attribute.PropertyName).GetValue(obj, null);
if (!valueToCompare.Equals(changedProperty.GetValue(obj, null)))
throw new Exception("the source and destination should not be equal");
}
}
Usage
var test = new ModelClass();
test.SourceCity = "1";
// Everything is ok
test.DestinationCity = "1";
// throws exception
test.DestinationCity ="2";
To simplify code I decided to omit a validation.
The best way to do this, is through of IValidatableObject. See http://msdn.microsoft.com/en-us/data/gg193959.aspx

Trigger an event from within another class

In .NET I have a class called Caption. I have another class called Gauge. Within the Gauge class I have a property defined as a Caption.
I am trying to figure out how to do the following:
When a certain property is changed in my Caption class how do I get it to execute a subroutine in the Gauge class? I am thinking I have to declare an event and AddHandlers to fire it off, but I can't think of how to accomplish this.
You'll want to look at implementing the INotifyPropertyChanged interface, which is designed exactly for the purpose - raising an event when a property of a class instance changes.
A good example of usage is given on this MSDN page.
// This class implements a simple customer type
// that implements the IPropertyChange interface.
public class DemoCustomer : INotifyPropertyChanged
{
// These fields hold the values for the public properties.
private Guid idValue = Guid.NewGuid();
private string customerName = String.Empty;
private string companyNameValue = String.Empty;
private string phoneNumberValue = String.Empty;
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
// The constructor is private to enforce the factory pattern.
private DemoCustomer()
{
customerName = "no data";
companyNameValue = "no data";
phoneNumberValue = "no data";
}
// This is the public factory method.
public static DemoCustomer CreateNewCustomer()
{
return new DemoCustomer();
}
// This property represents an ID, suitable
// for use as a primary key in a database.
public Guid ID
{
get
{
return this.idValue;
}
}
public string CompanyName
{
get {return this.companyNameValue;}
set
{
if (value != this.companyNameValue)
{
this.companyNameValue = value;
NotifyPropertyChanged("CompanyName");
}
}
}
public string PhoneNumber
{
get { return this.phoneNumberValue; }
set
{
if (value != this.phoneNumberValue)
{
this.phoneNumberValue = value;
NotifyPropertyChanged("PhoneNumber");
}
}
}
}
public class Caption
{
private int myInt;
public event EventHandler MyIntChanged;
private void OnMyIntChanged()
{
var handler = this.MyIntChanged;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
public int MyInt
{
get
{
return this.myInt;
}
set
{
if (this.myInt != value)
{
this.myInt = value;
this.OnMyIntChanged();
}
}
}
}
So now, in your guage class:
public class Guage
{
private Caption caption;
public Caption Caption
{
get
{
return this.caption;
}
set
{
if (this.caption!= value)
{
this.caption= value;
this.caption.MyIntChanged += new EventHandler(caption_MyIntChanged);
}
}
}
private void caption_MyIntChanged(object sender, EventArgs e)
{
//do what you gotta do
}
}

Categories