DataGrid calculated columns - c#

I am trying to transfer my excel app to WPF datagrid. I am going to enter data to Column A and in column B I would like to make calculation taking previus cell and current cell of A column and add Column B previus cell.
calculation example : B2 = B1 + (A2-A1). What is best approach of doing so?

Personally, I'd start by creating a class that represents the records and implement INotifyPropertyChanged on that class.
public class recordObject : INotifyPropertyChanged
{
private int a;
public int A
{
get
{
return a;
}
set
{
a = value;
OnPropertyChanged("A");
}
}
private int b;
public int B
{
get
{
return b;
}
set
{
b = value;
OnPropertyChanged("B");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Then, in your code behind on the window you're showing the datagrid, you'll want to subscribe to PropertyChanged on each object in the list. Then you'd have to manually compute the column values whenever those properties changed. Ick, I know, but it'd work.
The property changed event would look like:
void recordObject_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
var objectList = DataGrid.ItemsSource as List<recordObject>;
var myRecord = sender as recordObject;
if (objectList != null && myRecord != null)
{
int idx = objectList.IndexOf(myRecord);
// Perform your calculations here using idx to access records before and after the current record
// making sure to check for list boundaries for top and bottom.
// Also note that this will likely kick off cascading event calls so make sure you're only changing
// the previous or following record object.
}
}
If you hook this event onto all the records in your bound list, then it'll fire whenever any property is changed. In the class above, that'd apply to both A and B. You can filter which properties you're interested in monitoring through e.PropertyName (a simple string comparison) and guage the business logic accordingly. If you want to maintain encapsulation, or at least, put the business logic for the object on the object itself, this method could be a static one on the class recordObject. You'd have to provide for getting hold of the datagrid from that static method, though (likely through a static property on your window). So:
public static void recordObject_PropertyChanged(object sender, PropertyChangedEventArgs e)
and connected so:
record.PropertyChanged += new PropertyChangedEventHandler(recordObject.recordObject_PropertyChanged);

The best thing is to implement that logic in a class, and bind the grid to the respective properties. For instance:
class SomeData
{
int A { get; set; }
int B { get; set; }
int AminusB { get { return A - B; } }
}

Related

INotifyPropertyChanged in nested object

I have 2 main classes. The first class represents a Cell that can have values X, O or Empty. I have implemented INotifyPropertyChanged on this.
public class Cell : INotifyPropertyChanged
{
private Symbol state;
public Symbol State
{
get { return state; }
set
{
if (value == Symbol.X || value == Symbol.O)
state = value;
OnPropertyChanged("State");
}
}
public Cell()
{
state = Symbol.Empty;
}
public enum Symbol
{
X, O, Empty
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
The second class contains an object of this class and is also set as the datacontext for my main window.
public class Board
{
private Cell testCell;
public Cell TestCell
{
get { return testCell; }
set { testCell = value; }
}
public Board()
{
TestCell = new Cell();
}
public void Cell_Click(int cellNum)
{
TestCell.State = Cell.Symbol.O;
}
}
In my mainwindow I have set the datacontext as board, and also contains a button_click function.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new Board();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Board board = this.DataContext as Board;
board.Cell_Click(cellNum);
}
}
In my XAML I have bound to Cell object within board using a button style like this:
<Setter Property="Background" Value="{Binding TestCell,
Converter={StaticResource BGConverter}}"/>
BGConverter is a custom converter that accepts a Cell object and converts it into a Colors object. I believe I am indeed directly binding to an object that has INotify implemented, so there's no issue of nested objects. However the binding doesn't reflect changes when I click. When debugging, I found that PropertyChanged event is always null.
The closest answer I found for this is that the event will be subscribed to only if the class Cell is my datacontext. Atleast that's what I understood. How can I correct this problem?
Also I am fresh out of college, currently learning WPF on a new job, so any general recommendations are welcome too.
Thanks
Simply bind to TestCell.State instead of TestCell
I'm pretty new at this myself, but I believe your data context needs to implement INotifyPropertyChanged as well.
That is, your Board class needs to listen to the PropertyChanged event of the cells and fire its own PropertyChanged event when this happens.

Creating extra presentation properties for ItemsSource items

I have an ObservableCollection of items bound to a listbox as the ItemsSource.
Some of these items are also located in another collection on the same ViewModel (call it CollectionTwo).
I want to be able to take the count of the item in Collection2 and display it for the respective item in CollectionOne. When CollectionTwo properties change (ie the Count), it must also be reflected back to CollectionOne.
I would guess the best way to do this in MVVM is to wrap items in CollectionOne with a viewmodel class with an extra Count property on it. Can someone point me to a good example of this? Or perhaps another method to tackle this problem that won't hugely weigh down my ItemsSource performance.
Thanks!
You can use inheritance to create a custom collection along these lines...
public class MyCollection<T> : ObservableCollection<T>, INotifyPropertyChanged
{
// implementation goes here...
//
private int _myCount;
public int MyCount
{
[DebuggerStepThrough]
get { return _myCount; }
[DebuggerStepThrough]
set
{
if (value != _myCount)
{
_myCount = value;
OnPropertyChanged("MyCount");
}
}
}
#region INotifyPropertyChanged Implementation
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string name)
{
var handler = System.Threading.Interlocked.CompareExchange(ref PropertyChanged, null, null);
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
#endregion
}
This is a class that wraps an Observable Collection and puts a custom property in it. The property participates in change notification, but that depends upon your design.
To wire it up, you can do something like this...
public MyCollection<string> Collection1 { get; set; }
public MyCollection<string> Collection2 { get; set; }
public void Initialise()
{
Collection1 = new MyCollection<string> { MyCount = 0 };
Collection2 = new MyCollection<string> { MyCount = 0 };
Collection2.CollectionChanged += (s, a) =>
{
// do something here
};
}
You can also do something like...
Collection1.PropertyChanged += // your delegate goes here

Polling an object's public variable

I would like to notify a program immediately when there is a change in a bool variable that is a public variable of an object. For example;
say, an instance of class conn is created within a windows form application.
there is a Ready variable, a public variable of the class conn is present.
I would like to get notified whenever there is a change in this variable.
I did a quick research to solve this problem within stackoverflow but the answers suggested the use of property, which, I think is not suitable for my application.
I will assume you are referring to a field when you say public variable.
With few exceptions, it is preferable to not have public fields in C# classes, but rather private fields with public accessors:
class BadClass
{
public int Value; // <- NOT preferred
}
class GoodClass
{
private int value;
public int Value
{
get { return this.value; }
set { this.value = value; }
}
}
One of the reasons to structure your code this way is so you can do more than one thing in the property's getter and setters. An example that applies to your scenario is property change notification:
class GoodClass : INotifyPropertyChanged
{
private int value;
public int Value
{
get { return this.value; }
set
{
this.value = value;
this.OnPropertyChanged("Value");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string name)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(name);
}
}
}
If you were to implement your class like this, you could use it this way:
void SomeMethod()
{
var instance = new GoodClass();
instance.PropertyChanged += this.OnPropertyChanged;
}
void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Value")
{
// Do something here.
}
}
If you change the Value property, not only will it change the value of the underlying field, but it will also raise the PropertyChanged event, and call your event handler.
You want to use the Observer pattern for this. The most straight forward way to do this in .NET is the event system. In the class conn, create an event:
public event EventHandler ReadyChanged;
and then when you create an instance of conn, subscribe to that event:
o.ReadyChanged += (s, e) =>
{
// do something
}
and then finally, when the flag changes in conn, fire the event via a new method named OnReadyChanged:
protected virtual void OnReadyChanged()
{
if (ReadyChanged != null) { ReadyChanged(this, new EventArgs()); }
}

How to let a parent class know about a change in its children?

This is an example code:
public class MyParent : INotifyPropertyChanged
{
List<MyChild> MyChildren;
public bool IsChanged
{
get
{
foreach (var child in MyChildren)
{
if (child.IsChanged) return true;
}
return false;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaiseChanged(string propName)
{
if (PropertyChanged != null)
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propName));
}
}
public class MyChild : INotifyPropertyChanged
{
private int _Value;
public int Value
{
get
{
return _Value;
}
set
{
if (_Value == value)
return;
_Value = value;
RaiseChanged("Value");
RaiseChanged("IsChanged");
}
}
private int _DefaultValue;
public int DefaultValue
{
get
{
return _DefaultValue;
}
set
{
if (_DefaultValue == value)
return;
_DefaultValue = value;
RaiseChanged("DefaultValue");
RaiseChanged("IsChanged");
}
}
public bool IsChanged
{
get
{
return (Value != DefaultValue);
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaiseChanged(string propName)
{
if (PropertyChanged != null)
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propName));
}
}
Let's say I now have two instances of my classes, one as myParent, and the other as myChild.
I have two visual elements, that each have a property bound to the IsChnaged property of my instances; ElementA bound to myParent.IsChanged and ElementB bound to myChild.IsChanged.
When myChild.Value differs from its default value, the myChild.IsChanged is set to true and the ElementB is updated accordingly.
What I need is when either of the myParent children (which here is only one) have their IsChanged value set to true, its own (the parent's) IsChanged value be set to true and its corresponding
element (ElementA here) be updated accordingly.
The myParent.IsChanged is only read once (when the binding is set) and it has no sense about its children changing. Where should i put the RaiseChanged("IsChanged") for MyParent? How can I let the parent know when its children have changed?
Thanks in advance
INotifyPropertyChanged has already provided the mechanism for you: the PropertyChanged event. Just have the parent add a handler to its children's PropertyChanged, and then in that handler call RaiseChanged("IsChanged");
Also, you may want to put the INotifyPropertyChanged implementation in a base class, and have your (what appear to be) ViewModels inherit from that. Not required for this option, of course, but it will make the code a little cleaner.
Update: In the parent object:
// This list tracks the handlers, so you can
// remove them if you're no longer interested in receiving notifications.
// It can be ommitted if you prefer.
List<EventHandler<PropertyChangedEventArgs>> changedHandlers =
new List<EventHandler<PropertyChangedEventArgs>>();
// Call this method to add children to the parent
public void AddChild(MyChild newChild)
{
// Omitted: error checking, and ensuring newChild isn't already in the list
this.MyChildren.Add(newChild);
EventHandler<PropertyChangedEventArgs> eh =
new EventHandler<PropertyChangedEventArgs>(ChildChanged);
newChild.PropertyChanged += eh;
this.changedHandlers.Add(eh);
}
public void ChildChanged(object sender, PropertyChangedEventArgs e)
{
MyChild child = sender as MyChild;
if (this.MyChildren.Contains(child))
{
RaiseChanged("IsChanged");
}
}
You don't actually have to add anything to the child class, since it is already raising the correct event when it changes.
Doing this kind of communication can be tricky, especially if you want to avoid memory leaks due to the event handlers that you hook up. There is also the case of handling items that are added / removed from the collection.
I've really enjoyed the power and simplicity of the Continuous LINQ project on codeplex. It has some very rich features for setting up "Reactive Objects", "Continuous Values", and "Continuous Collections". These let you define your criteria as a Linq expression and then let the CLINQ library keep the underlying values up to date in real time.
In your case, you could set up the parent with a ContinuousFirstOrDefault() linq query that watched for any child where "IsChanged == true". As soon as a child sets the value to true and raises PropertyChanged, the continuous value will detect the change and raise a corresponding PropertyChanged in the parent.
The benefits:
Weak references and weak events are used to prevent the event handlers in the parent from locking the child in memory. It can get very messy to add / remove these handlers from all the children.
You can declare the dependency in the parent without need to make special changes in the child or make the child aware of the parent. Rather, the child just needs to properly implement INotifyPropertyChanged. This puts the "logic" close to the object that cares, rather than spreading event craziness and inter-dependencies all over the code.
Here's what the code might look like:
public class MyParent : INotifyPropertyChanged
{
private ObservableCollection<MyChild> _MyChildren;
private ContinuousValue<MyChild> _ContinuousIsChanged = null;
public MyParent()
{
_MyChildren = new ObservableCollection<MyChild>();
// Creat the ContinuousFirstOrDefault to watch the MyChildren collection.
// This will monitor for newly added instances,
// as well as changes to the "IsChanged" property on
// instances already in the collection.
_ContinuousIsChanged = MyChildren.ContinuousFirstOrDefault(child => child.IsChanged);
_ContinuousIsChanged.PropertyChanged += (s, e) => RaiseChanged("IsChanged");
}
public ObservableCollection<MyChild> MyChildren
{
get { return _MyChildren; }
}
public bool IsChanged
{
get
{
// If there is at least one child that matches the
// above expression, then something has changed.
if (_ContinuousIsChanged.Value != null)
return true;
return false;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaiseChanged(string propName)
{
if (PropertyChanged != null)
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propName));
}
}
public class MyChild : INotifyPropertyChanged
{
private int _Value;
public int Value
{
get
{
return _Value;
}
set
{
if (_Value == value)
return;
_Value = value;
RaiseChanged("Value");
RaiseChanged("IsChanged");
}
}
private int _DefaultValue;
public int DefaultValue
{
get
{
return _DefaultValue;
}
set
{
if (_DefaultValue == value)
return;
_DefaultValue = value;
RaiseChanged("DefaultValue");
RaiseChanged("IsChanged");
}
}
public bool IsChanged
{
get
{
return (Value != DefaultValue);
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaiseChanged(string propName)
{
if (PropertyChanged != null)
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propName));
}
}
The above code sets up the ContinuousFirstOrDefault in the constructor so that it is always monitoring. However, in some cases you can optimize this by lazily instantiating the ContinuousFirstOrDefault only when the getter for "IsChanged" is called. That way you don't start monitoring for changes until you know that some other piece of code actually cares.
You can simplify things for yourself by storing your children in an ItemObservableCollection<T>, as discussed in this answer. That would allow you to do this:
private ItemObservableCollection<MyChild> children;
public MyParent()
{
this.children = new ItemObservableCollection<MyChild>();
this.children.ItemPropertyChanged += delegate(object sender, PropertyChangedEventArgs e)
{
if (string.Equals("IsChanged", e.PropertyName, StringComparison.Ordinal))
{
this.RaisePropertyChanged("IsChanged");
}
};
}
Something I do not see in your code sample provide is an actually reference of parent to child. It is not enough to simply have interface to communicate through, but you must also create the reference. Something like myChild.parent = this; followed by the binding of the event handlers across the channel, in the "parent" property of the child object it would look like:
public INotifyPropertyChanged parent
{
get{return _parent;}
set
{
_parent = value;
this.PropertyChanged += _parent.RaiseChanged();
}
}
I don't have enough context to perfect this code for you but this should move you in the right direction.

How to implement DataTable property with INotifyPropertyChanged

I have created WPF MVVM application, and set WPFToolkit DataGrid binding to DataTable so I want to know how to implement DataTable property to notify changed. Currently my code is like below.
public DataTable Test
{
get { return this.testTable; }
set
{
...
...
base.OnPropertyChanged("Test");
}
}
public void X()
{
this.Test.Add(...); // I suppose this line will call to getter first (this.Test = get Test) and then it will call add letter, this mean that setter scope will never fire.
base.OnPropertyChanged("Test"); // my solution is here :) but I hope it has better ways.
}
Is it has another solution for this problem?
There are 2 ways your Table data could change: Either an element could be added/removed from the collection, or some properties from within an element could change.
The first scenario is easy to handle: make your collection an ObservableCollection<T>. Invoking .Add(T item) or .Remove(item) on your table will fire a change notification through to the View for you (and the table will update accordingly)
The second scenario is where you need your T object to implement INotifyPropertyChanged...
Ultimately your code should look something like this:
public class MyViewModel
{
public ObservableCollection<MyObject> MyData { get; set; }
}
public class MyObject : INotifyPropertyChanged
{
public MyObject()
{
}
private string _status;
public string Status
{
get { return _status; }
set
{
if (_status != value)
{
_status = value;
RaisePropertyChanged("Status"); // Pass the name of the changed Property here
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
}
}
Now set the datacontext of your View to be an instance of your ViewModel, and bind to the collection, like:
<tk:DataGrid
ItemsSource="{Binding Path=MyData}"
... />
Hope this helps :)
Ian

Categories

Resources