When i first assign the bidning to the Label in its constructor, the Label binds correctly and displays correct information based on current ComponentData value of CurrentMarket class. However when ComponentData changes, OnPropertyChanged event fires ok, but the ProperyChanged handler is always NULL. Can someone kindly suggest what am i doing wrong?
I have a label and i set the binding like this:
public StyledLabel(string Property, int i)
{
Binding BindingText = new System.Windows.Data.Binding(Property);
BindingText.Source = Statics.CurrentMarket.ComponentData;
BindingText.Converter = new TextConverter();
this.SetBinding(Label.ContentProperty, BindingText);
}
Current market class looks like this:
public class CurrentMarket : INotifyPropertyChanged
{
string sMarket = "";
ComponentData cComponentData;
public string Market
{
set
{
sMarket = value;
OnPropertyChanged("Market");
ComponentData = SharedBoxAdmin.Components[sMarket];
}
get
{
return sMarket;
}
}
public ComponentData ComponentData
{
get { return cComponentData; }
set
{
cComponentData = value;
OnPropertyChanged("ComponentData");
}
}
public CurrentMarket()
{
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string info)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(info));
}
}
}
Thanks!
Try specifying the property name that you want to bind to as the Path of the Binding (rather than as part of the Source):
Binding BindingText = new System.Windows.Data.Binding(Property);
BindingText.Source = Statics.CurrentMarket;
BindingText.Path = new PropertyPath("ComponentData");
BindingText.Converter = new TextConverter();
this.SetBinding(Label.ContentProperty, BindingText);
Related
I'm having a problem with subscribing to PropertyChangedEventHandler event of a property on a bound instance of my class.
Here is the setup:
XAML:
<CheckBox IsChecked="{Binding MyObservableClassInstance.BooleanProperty}"/>
DataContext class property:
public MyObservableClass MyObservableClassInstance
{
get { return _myClassInstance; }
set
{
_myClassInstance= value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("MyObservableClassInstance"));
}
}
the initialisation and subscription to PropertyChanged event (this subscribed method is never reached):
MyObservableClassInstance = new MyObservableClass();
MyObservableClassInstance.PropertyChanged += OnMyObservableClassPropertyChanged; // <--- This method is never hit
my observable class: (the BooleanProperty is working normally with the the XAML checkbox binding)
public class MyObservableClass : INotifyPropertyChanged
{
bool _mybool = false;
public event PropertyChangedEventHandler PropertyChanged;
public bool BooleanProperty
{
get { return _mybool; }
set
{
_mybool = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("BooleanProperty")); // <--- This is reached normally on checking/unchecking the checkbox
}
}
}
So why is my OnMyObservableClassPropertyChanged method never reached upon Invoking the PropertyChanged event?
You have to attach (and detach) the handler method to the PropertyChanged event whenever the MyObservableClass property value changes.
public MyObservableClass MyObservableClassInstance
{
get { return _myClassInstance; }
set
{
if (_myClassInstance != null)
{
_myClassInstance.PropertyChanged -= OnMyObservableClassPropertyChanged;
}
_myClassInstance = value;
if (_myClassInstance != null)
{
_myClassInstance.PropertyChanged += OnMyObservableClassPropertyChanged;
}
PropertyChanged?.Invoke(
this, new PropertyChangedEventArgs(nameof(MyObservableClassInstance)));
}
}
I try to binding textblock usercontrol with property of my class, but it only works at initial stage, I have implement IPropertyChnaged in my class.
In my class, _Feedbackpos (field of property) would change in background, I don't know how to solve this problem.
my class
public class TestControl : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyname)
{
if(PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyname));
}
}
private double _Feedbackpos;
public double Feedbackpos
{
get
{
return _Feedbackpos;
}
set
{
_Feedbackpos = value;
NotifyPropertyChanged("Feedbackpos");
}
}
//it's a callback function, it would excute when detect feedback position of controller change
private void ReadFeedbackpos()
{
_Feedbackpos = Controller.Read();
}
}
application windows
TestControl TestDll = new TestControl();
Binding BindingTxtBlk = new Binding(){Source= TestDll, Path = new Property("Feedbackpos")};
FeedbackPosTxtBlk.Setbinding(Textblock.TextProperty,BindingTxtBlk);
Change the function ReadFeedbackpos() to
private void ReadFeedbackpos()
{
Feedbackpos = Controller.Read();
}
Otherwise NotifyPropertyChanged("Feedbackpos"); will never get called.
What is the best way to bind a property to a control so that when the property value is changed, the control's bound property changes with it.
So if I have a property FirstName which I want to bind to a textbox's txtFirstName text value. So if I change FirstName to value "Stack" then the property txtFirstName.Text also changes to value "Stack".
I know this may sound a stupid question but I'll appreciate the help.
You must implement INotifyPropertyChanged And add binding to textbox.
I will provide C# code snippet. Hope it helps
class Sample : INotifyPropertyChanged
{
private string firstName;
public string FirstName
{
get { return firstName; }
set
{
firstName = value;
InvokePropertyChanged(new PropertyChangedEventArgs("FirstName"));
}
}
#region Implementation of INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
public void InvokePropertyChanged(PropertyChangedEventArgs e)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, e);
}
#endregion
}
Usage :
Sample sourceObject = new Sample();
textbox.DataBindings.Add("Text",sourceObject,"FirstName");
sourceObject.FirstName = "Stack";
A simplified version of the accepted answer that does NOT require you to type names of properties manually in every property setter like OnPropertyChanged("some-property-name"). Instead you just call OnPropertyChanged() without parameters:
You need .NET 4.5 minimum.
CallerMemberName is in the System.Runtime.CompilerServices namespace
public class Sample : INotifyPropertyChanged
{
private string _propString;
private int _propInt;
//======================================
// Actual implementation
//======================================
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
//======================================
// END: actual implementation
//======================================
public string PropString
{
get { return _propString; }
set
{
// do not trigger change event if values are the same
if (Equals(value, _propString)) return;
_propString = value;
//===================
// Usage in the Source
//===================
OnPropertyChanged();
}
}
public int PropInt
{
get { return _propInt; }
set
{
// do not allow negative numbers, but always trigger a change event
_propInt = value < 0 ? 0 : value;
OnPropertyChanged();
}
}
}
Usage stays the same:
var source = new Sample();
textbox.DataBindings.Add("Text", source, "PropString");
source.PropString = "Some new string";
Hope this helps someone.
I would like to cache some UI-specific properties only at the time an object is DataBound, if it gets bound.
Say I have
public interface IAmA<T> ()
{
T Value {get;set;}
}
public class MyString : IAmA<string>, INotifyPropertyChanged {
private string _value = String.Empty;
public virtual string Value
{
get
{
return this._value;
}
set
{
this._value = value;
OnPropertyChanged();
}
}
public virtual event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
}
}
Is it possible to implement an action or event to fire at the time the object is databound?
event Action OnDataBound { ... }
So I can detect, say, when
MyString myStrObj = new MyString("text");
myStrObj.OnDataBound += CacheUIElements();
Do.OtherStuff();
otherObj.DataSource = myStrObj; //causes CacheUIElements() to fire
You can very well do it in the property setter and call the Delegate.
In above case it will be for the OtherObj.DataSource. Because you want the Action to get triggered when you are setting the datasource. So it should be in the setter of whichever property where you want the action to trigger.
class OtherClass
{
DataSource
{
get{return _dataSource}
set
{
_dataSource = value;
OnPropertyChanged("DataSource");
OnDataBound();
}
}
}
If not, assuming OtherClass Implements OnPropertyChanged and triggers for DataSource like this, If its a framework element for sure it will implement NotifyPropertyChanged for DataSource because only then UI will refresh with the changes.
class OtherClass: INotifyPropertyChanged
{
DataSource
{
get{return _dataSource}
set
{
_dataSource = value;
OnPropertyChanged("DataSource");
}
}
}
Then you can subscribe to this event and check against the property name and trigger the OnDataBound(); e.g:
otherClassObj.PropertyChanged += OtherClassPropertyChanged()
private void OtherClassPropertyChanged(Obj sender, PropertyChangedEventargs e)
{
if(e.PropertyName = "DataSource")
{
OnDataBound();
}
}
I have a listbox which has items populated from a database. Now I want to update a listbox with a new string value each time I call the Add function.
I did this in 2 ways.
I added the new value to the database and updated the ViewModel class where the listbox is binded to. And this works fine. (see AddNewNameFirstWay method below)
I added the new value to the database, reloaded the values from the database and updated the ViewModel. But this doesn't work. (see AddNewNameSecondWay method below)
Here is my ViewModel code
public class ViewModel
{
private DBContext context = new DBContext("Data source=isostore:/names2.sdf");
private ObservableCollection<NameTable> nameCollection;
public ObservableCollection<NameTable> NameCollection
{
get
{
return nameCollection;
}
set
{
if (nameCollection != value)
{
nameCollection = value;
NotifyPropertyChanged();
}
}
}
public void AddNewNameSecondWay(string s)
{
NameTable t = new NameTable() { Name = s };
context.NameDatabaseTable.InsertOnSubmit(t);
context.SubmitChanges();
LoadFromDB();
}
public void AddNewNameFirstWay(string s)
{
NameTable t = new NameTable() { Name = s };
context.NameDatabaseTable.InsertOnSubmit(t);
context.SubmitChanges();
NameCollection.Add(t);
}
public void LoadFromDB()
{
var query = from i in context.NameDatabaseTable
select i;
NameCollection = new ObservableCollection<NameTable>(query);
}
private void NotifyPropertyChanged([System.Runtime.CompilerServices.CallerMemberName]string propertyName = null)
{
var tmp = PropertyChanged;
if (tmp != null)
tmp(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
Here is my XAML binding code
<ListBox ItemsSource="{Binding NameCollection, Mode=OneWay}" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name, Mode=OneWay}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
It seems to me that second method doesn't work, because the ObservableCollection memory reference changes. If this is correct, how to update the binding properly?
Reason I use the second method is that, I want to make sure all the DB constraints stands true for the values I insert.
You need to notify about the changes in property. Try this way for Framework 4.0,
Mode=OneWayToSource,UpdateSourceTrigger=PropertyChanged
Hope it helps...
Call OnPropertyChanged when you want notification about changes in your collection:
OnPropertyChanged("NameCollection")
Your ViewModel:
public class ViewModel: INotifyPropertyChanged
{
private DBContext context = new DBContext("Data source=isostore:/names2.sdf");
private ObservableCollection<NameTable> nameCollection;
public ObservableCollection<NameTable> NameCollection
{
get
{
return nameCollection;
}
set
{
if (nameCollection != value)
{
nameCollection = value;
OnPropertyChanged("NameCollection");
}
}
}
public void AddNewNameSecondWay(string s)
{
// your code
OnPropertyChanged("NameCollection");
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}