How do I bind an object to a dynamically created label? - c#

I am trying to bind but it doesn't seem to be working :/
my code:
void Binding(velocity Object, Label Output, string Field)
{
Binding newBinding = new Binding();
newBinding.Source = Object;
newBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
newBinding.Path = new PropertyPath(Field);
Output.SetBinding(Label.ContentProperty, newBinding);
}
Binding(newProjectile.CurrentVelocity, lbl_CurrentVelOutput, "Magnitude"); // how i call it
Thanks a bunch!
edit: i dont get an errror, its just that on the output the label doesnt change.
edit: i have tried looking for how to implement the INotifyChange interface and got something like this
public class velocity : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler Handler = PropertyChanged;
if (Handler != null)
{
Handler(this, new PropertyChangedEventArgs(name));
}
}
public double Velocity
{
get { return Magnitude; }
set
{
Magnitude = value;
OnPropertyChanged("10");
}
}
but i have no idea what i am doing.

Your binding should work just fine, but if you want changes to that Magnitude property to automatically show up in your view, then you'll have to let WPF know about those changes. That's where the INotifyProperty interface comes in, as it allows your code to let WPF known which properties have been changed:
// In C#, the common convention is to give classes CamelCased names:
public class Velocity : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
// Local variables and method arguments are also camelCased,
// but they start with a lower-case character:
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
// Properties with default getters and setters automatically get a 'backing field',
// but we can't use that because we need to call OnPropertyChanged, so we'll have to
// manually write out things. Normally, you'd give the backing field a name similar
// to the property, so it's obvious that they belong together:
private double _magnitude;
public double Magnitude
{
get { return _magnitude; }
set
{
_magnitude = value;
// Here, you need to pass in the *name* of the property that's being changed,
// so WPF knows which views it needs to update (WPF can fetch the new value
// by itself):
OnPropertyChanged("Magnitude");
}
}
}

Related

INotifyPropertyChanged does't work when field of property change internally

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.

Bind a Class property to controls Winform - C# [duplicate]

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.

OnPropertyChanged for nested properties

I have the following class as my DataContext of my UserControl:
public class ModelBase<T> : INotifyPropertyChanged where T : class
{
public T Model { get; set; }
public void UpdateUI()
{
OnPropertyChanged(string.Empty);
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
I am setting Model as an arbitrary class the contains primitive types.
I seem to have the binding done correctly, because I can see that the properties are being populated as I change them in the UI.
But the problem is that when I change the properties from code behind, it won't update the view with it, even after calling UpdateUI(). I verified the properties in the DataContext of the UI (with WPF/XAML inspection software) and they have the correct values.
I believe it has something to do with the fact that it's a nested class inside the DataContext, because I tried adding properties to ModelBase to test it, and the bindings worked fine when I called UpdateUI().
I'm creating the controls/bindings and adding it to the UserControl in the code behind, I'm not sure if this would cause a problem:
var textBox = new TextBox();
// Setup Binding
var binding = new Binding
{
Source = myModelBase.Model,
Path = new PropertyPath(nameOfProperty),
Mode = BindingMode.TwoWay,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
};
BindingOperations.SetBinding(textBox, TextBox.TextProperty, binding);
myUserControl.Content.Children.Add(textBox);
To have TwoWay binding you will have to have the following:
backing fields
public properties in which the setters raise a property change
notification.
a Model that implements INotifyPropertyChanged interface or inherits
from a class that implements it
Here is a nice way to do it:
rewrite your ModelBase to be (based on Implementing INotifyPropertyChanged - does a better way exist?):
public class ModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
//make sure we fire the event only when newvalue!=oldvalue
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
field = value;
OnPropertyChanged(propertyName);
return true;
}
}
and use it as
class Model:ModelBase{
//example for a property that is appropriate for 2 way bidning
private string _prop;
public string prop{
get{return _prop;}
set{SetField(ref _prop,value);}
}
}
if this is not sufficient please explain why it is not.
Update:based on what you want, you are doing it almost right your way but its just that you are not specifying the PropertyPath correctly, it should be "Model."+nameOfProperty and notice that you don't need to set the Source = myModelBase unless your container DataContext is not set to it.
So:
var binding = new Binding
{
Path = new PropertyPath("Model."+nameOfProperty),
Mode = BindingMode.Default,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
};
Or :
var binding = new Binding
{
Source = myModelBase,
Path = new PropertyPath("Model."+nameOfProperty),
Mode = BindingMode.Default,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
};
not sure if that will work but its probably the problem, otherwise your idea is fine.

Detecting when PropertyChangedEventHandler changes

My PropertyChanged event is getting set properly when I watch the variable, but somewhere in code it gets reset to null and I have no idea how to figure out where this is happening.
Here is come code:
public event PropertyChangedEventHandler PropertyChanged;
//this is in the NotifyTaskCompletion class, as used from the blog
// http://msdn.microsoft.com/en-us/magazine/dn605875.aspx
private async Task WatchTaskAsync(Task task)
{
try
{
await task; //After this task, PropertyChanged gets set to a non-null method("Void OnPropertyChanged()")
}
catch
{
}
//PropertyChanged, which was set to a value after the task was run, and still not null during IdentifyCompleted getting set, is now null here
var propertyChanged = PropertyChanged;
if (propertyChanged == null)
return;
//other code
}
//My Watch variable of PropertyChanged is still good after this setter is run.
public NotifyTaskCompletion<GraphicCollection> IdentifyCompleted
{
get { return _IdentifyCompleted; }
set
{
_IdentifyCompleted = value;
// _IdentifyCompleted.PropertyChanged+= new PropertyChangedEventHandler(this, new PropertyChangedEventArgs("IdentifyCompleted"));
// NotifyPropertyChanged();
}
}
My main issue is that I cannot use a {set;get;} on PropertyChanged to attempt to identify WHERE it is getting set to null. So my main question, unless anyone sees something that is obviously wrong, is how would I go about finding out where it is getting set to null? Thank you for any assistance.
EDIT
As per the last posters suggestion, I set my code as follows:
private PropertyChangedEventHandler _propertyChanged;
public event PropertyChangedEventHandler PropertyChanged
{
add { _propertyChanged += value; }
remove { _propertyChanged -= value; }
}
And here is the issue.
//this is in my View Model. The ViewModel CONTAINS NotifyTaskCompletion<GraphicCollection> IdentifyCompleted which in turn implements INotifyPropertyChanged and has its own PropertyChanged that is not getting set
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
//This line sets the PopertyChanged in the view model AND in the NotifyTaskCompletion class somehow, but I don't know how it is setting it properly in the NotifyTaskCompletion class in my other project where this code works, When I step through this line in my code, it doesn't trigger
//the add{} of the PropertyChanged in NotifyTaskCompletion, but it DOES in my other project...
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
So with all that said, I can now see what line SHOULD be working, but I have no idea WHY it isn't working. Any other ideas? Thanks for the help so far.
You can write your own event accessors:
private PropertyChangedEventHandler propertyChanged;
public event PropertyChangedEventHandler PropertyChanged {
add { propertyChanged += value; }
remove { propertyChanged -= value; }
}
You can then set breakpoints.
Note that this is not thread-safe.

Image binding in WPF

I have an Image control that is supposed to do a slide show.
Here are the binding I used to achieve this:
Binding mapBinding = new Binding();
mapBinding.Source = slideView;
mapBinding.Path = new PropertyPath("ImageDrawing");
sliderImage.SetBinding(System.Windows.Controls.Image.SourceProperty, mapBinding);
And a class SlideImage
public class SlideImage : INotifyPropertyChanged {
public ImageSource ImageDrawing{get;set;}
public void ChangeImage(){
// Load another image
// Update ImageDrawing
// Fire property changed event
}
public event PropertyChangedEventHandler PropertyChanged;
}
I found many examples on the net using the UpdateSourceTrigger to listen for data source changes. The only problem is the Image control does not have that property.
How do I hook up my sliderImage control to update on SlideImage.PropertyChanged?
It probably will update automatically, if you're actually calling PropertyChanged when calling the setter of ImageDrawing.
You aren't firing PropertyChanged for your ImageDrawing property in the code you've provided. Try this:
private ImageSource imageDrawing;
public ImageSource ImageDrawing
{
get { return imageDrawing; }
set
{
imageDrawing = value;
RaisePropertyChanged("ImageDrawing");
}
}
private void RaisePropertyChanged(string propertyName)
{
if(PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}

Categories