I'm attempting to bind a windows form label to a variable. when i run that code lable1 was displayed as 50 but when i increment using button1 it doesn't change to 51. here is my attemp
int x = 50;
public int X
{
get { return x; }
set { x = value; }
}
public Form1()
{
InitializeComponent();
label1.DataBindings.Add("Text", this, "X", true, DataSourceUpdateMode.OnPropertyChanged);
}
private void button1_Click(object sender, EventArgs e)
{
X++;
}
TIA
You can put your data in another class that implements INotifyPropertyChanged so that the UI will be notified and updated:
public partial class Form1 : Form
{
DataClass dc;
public Form1()
{
InitializeComponent();
dc = new DataClass();
label1.DataBindings.Add("Text", dc, "X", true, DataSourceUpdateMode.OnPropertyChanged);
}
private void button1_Click(object sender, EventArgs e)
{
dc.X++;
}
}
public class DataClass : INotifyPropertyChanged
{
int x = 50;
public int X
{
get { return x; }
set
{
x = value;
NotifyPropertyChanged("X");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(info));
}
}
}
int X = 50;
public Form1() {
InitializeComponent();
label1.Text = X.ToString();
}
private void button1_Click(object sender, EventArgs e) {
X += 1;
label1.Text = X.ToString();
}
Your Class Form must be implement the INotifyPropertyChanged interface, like this:
public partial class Form1 : Form, INotifyPropertyChanged
{
int x = 50;
public int X
{
get { return x; }
set { x = value; OnPropertyChanged("X"); }
}
private void Form1_Load(object sender, EventArgs e)
{
label1.DataBindings.Add("Text", this, "X", true, DataSourceUpdateMode.OnPropertyChanged);
}
private void button1_Click(object sender, EventArgs e)
{
X++;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string property)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
Related
How can I listen in class B to the PropertyChanged events from class A? I would like to listen to changes of a property from class A.
class A : INotifyPropertyChanged
{
private int _x;
public int X
{
get => _x;
set
{
if (_x == value) return;
_x = value;
OnPropertyChanged(nameof(X));
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
class B
{
public B(int x)
{
// In this class I want to listen to changes of the property X from class A
}
}
Just listen to the event:
class B
{
public A _myA;
public B(int x)
{
_myA = new A();
_myA.PropertyChanged += A_PropertyChanged;
}
private void A_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName != nameof(_myA.X)) return;
}
}
I'm trying to make a list of numericUpDown.value and, when I press the button, it sets a random value from the presenter; but, when I press the button nothing happen, I see the value change but I think it just replace the numeric control with a value instead of set value.
The view :
public partial class Form1 : Form, IForm1
{
public List<decimal> _valueList { get; set; }
public Form1()
{
InitializeComponent();
this._valueList = new List<decimal> { numericUpDown1.Value, numericUpDown2.Value, numericUpDown3.Value, numericUpDown4.Value, numericUpDown5.Value, numericUpDown6.Value };
}
public List<decimal> ValueList
{
get => _valueList; set => _valueList = value;
}
public event EventHandler ButtonClick;
private void button1_Click(object sender, EventArgs e)
{
ButtonClick?.Invoke(sender, e);
}
}
Interface:
public interface IForm1
{
List<decimal> ValueList { get; set; }
event EventHandler ButtonClick;
}
Presenter:
public class PresenterForm1
{
private IForm1 _form1;
public PresenterForm1(IForm1 form1)
{
_form1 = form1;
form1.ButtonClick += ButtonClick;
}
private void ButtonClick(object sender, EventArgs e)
{
var random = new Random();
for(int i = 0; i < 6; i++)
{
_form1.ValueList[i] = random.Next(0, 10);
}
}
If I change the type to List<NumericUpDown> it works, but I think this is the wrong way:
foreach (var item in _form1.ValueList)
{
item.Value = random.Next(0, 99);
}
I have use the following code snippet for Creating ObservableCollection binded to the DataGrid.
public class Test:INotifyPropertyChanged
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value;OnpropertyChanged("Name"); }
}
private string _city;
public string City
{
get { return _city; }
set
{
_city = value;OnpropertyChanged("City");}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
public void OnpropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
}
#endregion
}
class Data:INotifyPropertyChanged
{
private int customerID;
public int CustomerID
{
get { return customerID; }
set { customerID = value; OnpropertyChanged("CustomerID"); }
}
private bool isSelected;
public bool IsSelected
{
get { return isSelected; }
set { isSelected = value; OnpropertyChanged("IsSelected"); }
}
private ObservableCollection<Test> _collection;
public ObservableCollection<Test> Collection
{
get { return _collection; }
set { _collection = value;OnpropertyChanged("Collection" +
""); }
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnpropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
}
}
class ViewModel:NotificationObject
{
public ViewModel()
{
this.GDCSource = Getsource();
}
private ObservableCollection<Data> _gdcsource;
public ObservableCollection<Data> GDCSource
{
get { return _gdcsource; }
set { _gdcsource = value; RaisePropertyChanged("GDCSource");}
}
private ObservableCollection<Data> Getsource()
{
ObservableCollection<Data> items = new ObservableCollection<Data>();
if (items != null)
{
items.Add(new Data()
{
IsSelected = true,
CustomerID = 1,
});
items.Add(new Data()
{
IsSelected = true,
CustomerID = 2,
});
}
return items;
}
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ViewModel vmModel = new ViewModel();
this.datagrid.ItemsSource = vmModel.GDCSource;
vmModel.GDCSource.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(GDCSource_CollectionChanged);
}
void GDCSource_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
//Listen the collection changed event for underlying source
}
// add the object to the Collection property
private void Test_OnClick(object sender, RoutedEventArgs e)
{
(this.DataContext as ViewModel).GDCSource[0].Collection.Add(new Test() { Name = "Name1", City = "City1" });
(this.DataContext as ViewModel).GDCSource[0].Collection.Add(new Test() { Name = "Name1", City = "City1" });
(this.DataContext as ViewModel).GDCSource[0].Collection.Add(new Test() { Name = "Name1", City = "City1" });
}
}
It is possible to listen while adding Collection property in any event.
Thanks in advance
Regards,
Rajasekar
If you mean you want to register for event that is raised when item is added/deleted in observable collection you should look at CollectionChanged event
ObservableCollection<T>.CollectionChanged Event
Occurs when an item is added, removed, changed, moved, or the entire
list is refreshed.
You can extend your own version of ObservableCollection if you want and override the add method,
There you can fire any delegates or whatever you may want to register, the UI will update automatically using ObservableCollection with items added/removed you don't need to do anything for that,
I'm trying to create basic class which will allow different controls to bind-in and display some values.
I want to have static list of objects, where each object has some properties like caption, ticks counter, whatever.
Then I want to bind label to last added item to this list and datagridview to allow to see all of them.
Would be great if such solution could be for both winforms and wpf environments.
If you could point me what I'm doing wrong. Thanks.
Draft of the idea (one of many already tested and failed) below.
status class:
public class Status: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
//implementation of observable collection
private static ObservableCollection<Status> _list;
public static ObservableCollection<Status> List
{
get { return _list ?? (_list = new ObservableCollection<Status>{new Status()}); }
}
//object properties
public string Message { get; set; }
public bool Finished { get; set; }
//object views
public string View
{
get { return Message + "(" + Finished + ")" ; }
}
//object methods
public static Status Add(string message)
{
var result = new Status
{
Message = message,
Finished = false
};
List.Add(result);
return result;
}
public void Finish()
{
Finished = true;
}
}
form:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
label1.DataBindings.Add("Text", Status.List, "Message");
listBox1.DisplayMember = "View";
listBox1.DataSource = Status.List;
}
private void Button1_Click(object sender, EventArgs e)
{
label5.Text = Status.Add(textBox1.Text).Message;
textBox1.Text = "";
}
private void Button2_Click(object sender, EventArgs e)
{
((Status)listBox1.SelectedItem).Finish();
}
}
This did the trick:
using System;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Runtime.CompilerServices;
using WindowsFormsApplication2.Annotations;
namespace WindowsFormsApplication2
{
public class Item : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
#region Notyfier implementation
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
#region collection implemetation
public BindingList<Item> Items = new BindingList<Item>();
public string Count
{
get { return (Items.Count == 1)
? "1 item."
: Items.Count + " items."; }
}
public Item Current
{
get { return Items.Count == 0
? new Item {Colour = Color.Chartreuse} //default initial item
: Items.Last(); }
}
#endregion
#region object implemetation
protected object ID { get; set; }
public Color Colour { get; set; }
public void NewItem(Color color)
{
Items.Add(new Item
{
ID = Guid.NewGuid(),
Colour = color
});
OnPropertyChanged("Count");
OnPropertyChanged("Current");
}
#endregion
}
}
I've got some classes here that all more or less rely on each other. The relationships form kinda like a dependency tree:
class A {
List<B> _bs = new List<B>();
public int ValueOfA {
get {
return _bs.Sum(p => p.ValueOfB);
}
}
class B {
List<C> _cs = new List<C>();
public int ValueOfB {
get {
return _cs.Where(p => p.ValueOfC > 1).Sum(p => p.ValuOfC);
}
}
class C {
public int ValueOfC { get; set }
}
So, whenever _bs, _cs or ValueOfC change, every property relating to them should be notified as has changed, too, and hence be recalculated.
What's the best way of consistently and reliably achieving this goal? Is there by any chance a way to do this automatically?
You'll want to implement INotifyPropertyChanged with your class C. In the set of ValueOfC, you'll fire the event:
class C : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private int valueOfC;
public int ValueOfC
{
get { return valueOfC; }
set
{
valueOfC = value;
OnPropertyChanged(PropertyChanged);
}
}
protected virtual void OnPropertyChanged(PropertyChangedEventHandler handler)
{
if (handler != null)
handler(this, new PropertyChangedEventArgs("ValueOfC"));
}
}
I just tested it, and it works perfectly.
Having a protected virtual method fire the event for you is just common practice.
As a side note, if you want to do something if the lists change, you may want to look into using a BindingList or an ObservableCollection.
EDIT
I've written up a small example that does refresh the whole tree:
public class Bank : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private BindingList<Customer> customers = new BindingList<Customer>();
public int Worth
{
get { return customers.Sum(cust => cust.FullBalance); }
}
public Bank()
{
customers.ListChanged += new ListChangedEventHandler(customers_ListChanged);
}
void customers_ListChanged(object sender, ListChangedEventArgs e)
{
Console.WriteLine("A customer has changed.");
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs("Worth"));
}
public void Add(Customer c) { customers.Add(c); }
}
public class Customer : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private BindingList<Account> accounts = new BindingList<Account>();
public int FullBalance
{
get { return accounts.Sum(acc => acc.Balance); }
}
public Customer()
{
accounts.ListChanged += new ListChangedEventHandler(accounts_ListChanged);
}
void accounts_ListChanged(object sender, ListChangedEventArgs e)
{
Console.WriteLine("An account has changed.");
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs("FullBalance"));
}
public void Add(Account a) { accounts.Add(a); }
}
public class Account : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private int balance = 0;
public int Balance
{
get { return balance; }
set
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs("Balance"));
}
}
}
class Program
{
static void Main(string[] args)
{
Account a1 = new Account() { Balance = 5 };
Account a2 = new Account() { Balance = 10 };
Account a3 = new Account() { Balance = 15 };
Customer c1 = new Customer(); c1.Add(a1); c1.Add(a2);
Customer c2 = new Customer(); c2.Add(a3);
Bank b = new Bank(); b.Add(c1); b.Add(c2);
Console.WriteLine();
a1.Balance += 100;
}
}
Now you can write something like if (e.ListChangedType == ListChangedType.ItemChanged) in the event handlers, or something similar.