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)
{
}
Related
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.
I have properties CaretIndex and InputValue im my ViewModel which are used for Highlighting ComboBox Items which matches the text in PART_EditableTextBox of ComboBox.
So, I want them to be in a seperate file. So, I don't have to type them in each and every time I declare a new View. But problem here is that these CaretIndex and InputValue properties's setter part depends on another Class's another property named IsHighlighted and the class may change for each new collection of data.
I have a ViewModel as follows:
public class GroupsViewModel : INotifyPropertyChanged
{
public GroupsViewModel()
{
using (DBEntities db = new DBEntities())
{
GroupsAndCorrespondingEffects = (from g in db.Groups
select new GroupAndCorrespondingEffect
{
GroupName = g.Name,
CorrespondingEffect = g.Type_Effect.Name
}
).ToList();
GroupsAndCorrespondingEffects.Add
(
new GroupAndCorrespondingEffect
{
GroupName = " Primary",
CorrespondingEffect = ""
}
);
GroupsAndCorrespondingEffects = GroupsAndCorrespondingEffects.OrderBy(g => g.GroupName).ToList();
Items = (from e in db.Type_Effect
select e.Name).ToList();
}
}
public static GroupsViewModel CurrentInstance { get { return Instance; } }
private List<GroupAndCorrespondingEffect> _groupsAndCorrespondingEffects;
public List<GroupAndCorrespondingEffect> GroupsAndCorrespondingEffects
{
get
{
return _groupsAndCorrespondingEffects;
}
set
{
_groupsAndCorrespondingEffects = value;
OnPropertyChanged("GroupsAndCorrespondingEffects");
}
}
private int _caretIndex;
public int CaretIndex
{
get { return _caretIndex; }
set
{
_caretIndex = value;
OnPropertyChanged("CaretIndex");
for (int i = 0; i < GroupsAndCorrespondingEffects.Count; i++)
{
string WordToSearch = InputValue;
if (_caretIndex != 0 && _caretIndex > 0)
{
WordToSearch = InputValue.Substring(0, _caretIndex);
}
if (WordToSearch != null)
{
GroupsAndCorrespondingEffects[i].IsHighlighted = GroupsAndCorrespondingEffects[i].GroupName.StartsWith(WordToSearch);
}
}
}
}
private string _inputValue;
public string InputValue
{
get { return _inputValue; }
set
{
_inputValue = value;
OnPropertyChanged("GroupsAndCorrespondingEffects");
for (int i = 0; i < GroupsAndCorrespondingEffects.Count; i++)
{
string WordToSearch = _inputValue;
if (_caretIndex != 0 && _caretIndex > 0 && _caretIndex < _inputValue.Length)
{
WordToSearch = _inputValue.Substring(0, _caretIndex);
}
GroupsAndCorrespondingEffects[i].IsHighlighted = GroupsAndCorrespondingEffects[i].GroupName.StartsWith(WordToSearch);
}
}
}
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
The Helper Class that is used to get data in a different format (Get data in Two Columns for a comboBox.) is as below: (This class's IsHighLighted Property is referenced in the setter part of CaretIndex and InputValue.)
public class GroupAndCorrespondingEffect : INotifyPropertyChanged
{
private string _groupName;
public string GroupName
{
get
{
return _groupName;
}
set
{
_groupName = value;
OnPropertyChanged("GroupName");
}
}
private string _correspondingEffect;
public string CorrespondingEffect
{
get
{
return _correspondingEffect;
}
set
{
_correspondingEffect = value;
OnPropertyChanged("CorrespondingEffect");
}
}
private bool _isHighlighted;
public bool IsHighlighted
{
get
{
return _isHighlighted;
}
set
{
_isHighlighted = value;
OnPropertyChanged("IsHighlighted");
}
}
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
If I understand your question correctly, what you want to do is move the common bits like CaretIndex, and InputValue to an abstract base class.
Refer to below Sample code to see what I am saying:
Base Class
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private int _caretIndex;
public int CaretIndex
{
get { return _caretIndex; }
set
{
_caretIndex = value;
OnPropertyChanged("CaretIndex");
OnCaretIndexChanged();
}
}
private string _inputValue;
public string InputValue
{
get { return _inputValue; }
set
{
_inputValue = value;
OnPropertyChanged("InputValue");
OnInputValueChanged();
}
}
protected abstract void OnCaretIndexChanged();
protected abstract void OnInputValueChanged();
}
If you check the Setters for CaretIndex and InputValue, they are executing OnCaretIndexChanged and OnInputValueChanged abstract methods respectively - for which you will have implementation in the derived classes.
Now, your GroupViewModel will inherit from ViewModelBase and implement those two abstract methods.
public class GroupsViewModel : ViewModelBase
{
public GroupsViewModel()
{
using (DBEntities db = new DBEntities())
{
GroupsAndCorrespondingEffects = (from g in db.Groups
select new GroupAndCorrespondingEffect
{
GroupName = g.Name,
CorrespondingEffect = g.Type_Effect.Name
}
).ToList();
GroupsAndCorrespondingEffects.Add
(
new GroupAndCorrespondingEffect
{
GroupName = " Primary",
CorrespondingEffect = ""
}
);
GroupsAndCorrespondingEffects = GroupsAndCorrespondingEffects.OrderBy(g => g.GroupName).ToList();
Items = (from e in db.Type_Effect
select e.Name).ToList();
}
}
public static GroupsViewModel CurrentInstance { get { return Instance; } }
private List<GroupAndCorrespondingEffect> _groupsAndCorrespondingEffects;
public List<GroupAndCorrespondingEffect> GroupsAndCorrespondingEffects
{
get
{
return _groupsAndCorrespondingEffects;
}
set
{
_groupsAndCorrespondingEffects = value;
OnPropertyChanged("GroupsAndCorrespondingEffects");
}
}
protected override void OnCaretIndexChanged()
{
for (int i = 0; i < GroupsAndCorrespondingEffects.Count; i++)
{
string wordToSearch = InputValue;
if (CaretIndex != 0 && CaretIndex > 0)
{
wordToSearch = InputValue.Substring(0, CaretIndex);
}
if (wordToSearch != null)
{
GroupsAndCorrespondingEffects[i].IsHighlighted = GroupsAndCorrespondingEffects[i].GroupName.StartsWith(wordToSearch);
}
}
}
protected override void OnInputValueChanged()
{
OnPropertyChanged("GroupsAndCorrespondingEffects");
for (int i = 0; i < GroupsAndCorrespondingEffects.Count; i++)
{
string wordToSearch = InputValue;
if (CaretIndex != 0 && CaretIndex > 0 && CaretIndex < InputValue.Length)
{
wordToSearch = InputValue.Substring(0, CaretIndex);
}
GroupsAndCorrespondingEffects[i].IsHighlighted = GroupsAndCorrespondingEffects[i].GroupName.StartsWith(wordToSearch);
}
}
}
You can follow similar approach if you want to abstract away your IsHighlighted property from class GroupAndCorrespondingEffect.
Hope this helps or gives you some ideas.
UPDATE
Added Class Diagram
I have a MainPage.xaml where is ListBox and Button. When I click on the button then MainPage is navigated to AddPage.xaml. This page is for adding new items, there are two TextBoxes and submit Button. When I click on that submit Button,then data from TextBoxes are saved to XML file and then is called GoBack().
I need to refresh ListBox in my MainPage.xaml when Im going back from AddPage.xaml, but it doesnt work automaticly. How can I do that?
My MainViewModel.cs
public class MainViewModel : INotifyPropertyChanged
{
public ObservableCollection<Context> Contexts { get; private set; }
public MainViewModel()
{
this.Contexts = new ObservableCollection<Context>();
}
public bool IsDataLoaded
{
get;
private set;
}
public void LoadData()
{
try
{
var file = IsolatedStorageFile.GetUserStoreForApplication();
XElement xElem;
using (IsolatedStorageFileStream read = file.OpenFile("contexts.xml", FileMode.Open))
{
xElem = XElement.Load(read);
}
var contexts = from context in xElem.Elements("Context")
orderby (string)context.Element("Name")
select context;
foreach (XElement xElemItem in contexts)
{
Contexts.Add(new Context
{
Name = xElemItem.Element("Name").Value.ToString(),
Note = xElemItem.Element("Note").Value.ToString(),
Created = xElemItem.Element("Created").Value.ToString()
});
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
this.IsDataLoaded = true;
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
and Context.cs
public class Context : INotifyPropertyChanged
{
private string _name;
public string Name
{
get
{
return _name;
}
set
{
if (value != _name)
{
_name = value;
NotifyPropertyChanged("Name");
}
}
}
private string _note;
public string Note
{
get
{
return _note;
}
set
{
if (value != _note)
{
_note = value;
NotifyPropertyChanged("Note");
}
}
}
private string _created;
public string Created
{
get
{
return _created;
}
set
{
if (value != _created)
{
_created = value;
NotifyPropertyChanged("Created");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
You'll need to tell the main page that there is new data to reload.
At it's simplest, something like this:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (e.NavigationMode == NavigationMode.Back)
{
(this.DataContext as MainViewModel).LoadData();
}
}
Tip: You aren't raising a property changed notification for your View Model's properties.
On the load event of the MainPage, call LoadData. You should also clear the observable collection when you call the LoadData method before adding anything to it because simply loading the data will cause duplicate entries in your collection.
So I've got an odd bug I'm hoping someone can help me with.
I have the following code to grab some entities from WCF RIA Services, this is in Silverlight 4, though my guess is that doesn't make a difference.
What am I missing?
public class MyModel
{
...
public IEnumerable<MyEntity> Result { get; private set; }
public void Execute()
{
Context.Load(Query, LoadBehavior.RefreshCurrent, o =>
{
if (o.HasError)
{
ExecuteException = o.Error;
if (ExecuteError != null)
ExecuteError(this, EventArgs.Empty);
o.MarkErrorAsHandled();
}
else
{
//I've stepped through the code and the assignment is working
//Result != null
Result = o.Entities;
if (ExecuteSuccess != null)
ExecuteSuccess(this, EventArgs.Empty);
//Inside any Handler of ExecuteSuccess
//MyModel.Result == null
//However I set a break point after ExecuteSuccess is triggered,
//and once again MyModel.Result != null
}
if (ExecuteComplete != null)
ExecuteComplete(this, EventArgs.Empty);
ExecuteBusy = false;
}, false);
}
}
Everything works until I get to this point:
MyModel.ExecuteSuccess += (o,e) => {
//At this point MyModel.Result == null. but why?
var result = MyModel.Result;
};
Yeah I found the issue I was doing some crazy stuff in order to make MVVM + RIA Services more fun, in an inheriting class I was casting MyModel.Result to MyModel.Result as IEnumerable<TEntity>; which doesn't work. I used MyModel.Result.OfType<TEntity> instead. I'm posting all the code in case it's useful to someone else.
public abstract class RiaQuery : INotifyPropertyChanged
{
#region INotifyPropertyChanged values
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
#region Query
private EntityQuery _Query;
public EntityQuery Query
{
get { return _Query; }
private set
{
if (_Query != value)
{
_Query = value;
RaisePropertyChanged("Query");
}
}
}
#endregion
#region Result
private IEnumerable _Result;
public IEnumerable Result
{
get { return _Result; }
private set
{
if (_Result != value)
{
_Result = value;
RaisePropertyChanged("Result");
}
}
}
#endregion
#region ExecuteBusy
private bool _ExecuteBusy;
public bool ExecuteBusy
{
get { return _ExecuteBusy; }
private set
{
if (_ExecuteBusy != value)
{
_ExecuteBusy = value;
RaisePropertyChanged("ExecuteBusy");
}
}
}
#endregion
#region ExecuteCommand
private DelegateCommand _ExecuteCommand;
public DelegateCommand ExecuteCommand
{
get
{
if (_ExecuteCommand == null)
{
_ExecuteCommand = new DelegateCommand(o => Execute(o), o => !ExecuteBusy);
}
return _ExecuteCommand;
}
}
#endregion
#region ExecuteException
private Exception _ExecuteException;
public Exception ExecuteException
{
get { return _ExecuteException; }
private set
{
if (_ExecuteException != value)
{
_ExecuteException = value;
RaisePropertyChanged("ExecuteException");
}
}
}
#endregion
public event EventHandler ExecuteBegin;
public event EventHandler ExecuteComplete;
public event EventHandler ExecuteSuccess;
public event EventHandler ExecuteError;
protected DomainContext Context;
public bool CreateQueryEachTime { get; set; }
public RiaQuery(DomainContext context)
{
if (context == null) throw new ArgumentException("context");
Context = context;
}
public void Execute(object param)
{
ExecuteBusy = true;
if (ExecuteBegin != null)
ExecuteBegin(this, EventArgs.Empty);
if (CreateQueryEachTime || Query == null)
CreateQueryInternal();
Context.Load(Query, LoadBehavior.RefreshCurrent, o =>
{
if (o.HasError)
{
ExecuteException = o.Error;
if (ExecuteError != null)
ExecuteError(this, EventArgs.Empty);
o.MarkErrorAsHandled();
}
else
{
Result = o.Entities;
if (ExecuteSuccess != null)
ExecuteSuccess(this, EventArgs.Empty);
}
if (ExecuteComplete != null)
ExecuteComplete(this, EventArgs.Empty);
ExecuteBusy = false;
}, false);
}
private void CreateQueryInternal()
{
Query = CreateQuery();
}
protected abstract EntityQuery CreateQuery();
}
public abstract class RiaQuery<TContext> : RiaQuery
where TContext : DomainContext
{
new protected TContext Context
{
get { return base.Context as TContext; }
set { base.Context = value; }
}
public RiaQuery(TContext context) : base(context) { }
}
public abstract class RiaQuery<TContext,TEntity> : RiaQuery<TContext>
where TContext : DomainContext
where TEntity : Entity
{
new public EntityQuery<TEntity> Query
{
get { return base.Query as EntityQuery<TEntity>; }
}
new public IEnumerable<TEntity> Result
{
get { return base.Result.OfType<TEntity>(); }
}
public RiaQuery(TContext context) : base(context) { }
}
public class DelegateRiaQuery<TContext> : RiaQuery<TContext>
where TContext : DomainContext
{
protected Func<TContext, EntityQuery> CreateQueryDelegate;
public DelegateRiaQuery(TContext context, Func<TContext, EntityQuery> createQueryDelegate)
: base(context)
{
if (createQueryDelegate == null) throw new ArgumentException("createQueryDelegate");
CreateQueryDelegate = createQueryDelegate;
}
protected override EntityQuery CreateQuery()
{
return CreateQueryDelegate(Context);
}
}
public class DelegateRiaQuery<TContext, TEntity> : RiaQuery<TContext, TEntity>
where TContext : DomainContext
where TEntity : Entity
{
protected Func<TContext, EntityQuery<TEntity>> CreateQueryDelegate;
public DelegateRiaQuery(TContext context, Func<TContext, EntityQuery<TEntity>> createQueryDelegate) : base(context)
{
if (createQueryDelegate == null) throw new ArgumentException("createQueryDelegate");
CreateQueryDelegate = createQueryDelegate;
}
protected override EntityQuery CreateQuery()
{
return CreateQueryDelegate(Context);
}
}
Usage looks like this:
public class MyModel : INotifyPropertyChanged
{
...
public DelegateRiaQuery<MyContxt,MyEntity> MyModelOperation { get; private set; }
public MyModel()
{
var context = new MyContext();
MyModelOperation = new DelegateRiaQuery(context, c => c.GetMyModelEntitiesQuery(this.Property1));
}
}
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
}
}