I ran into a situation where I wanted to setup some data binding between a POCO property and a TextBox. You can do this with a BindingSource and a control's DataBindings collection, of course, but a BindingSource expects both a DataSource and DataMember, and is not POCO-friendly, really. (A BindingSource seems to expect a tabular data source instead of a single row, as it were.) So, I had a DataSource, but no DataMember.
I accomplished this with this a TextBox extension method using reflection, passing the POCO object and property to bind to as a string:
public static void Bind(this TextBox textBox, object dataObject, string propertyName)
{
PropertyInfo property = dataObject.GetType().GetProperty(propertyName);
textBox.Text = property.GetValue(dataObject, null).ToString();
textBox.TextChanged += delegate(object sender, EventArgs e)
{
PropertyInfo pi = dataObject.GetType().GetProperty(propertyName);
pi.SetValue(dataObject, textBox.Text, null);
};
}
In my situation, the calling code looks like this:
tbProjectConnection.Bind(_modelBuilder, "ProjectConnection");
tbOutputFolder.Bind(_modelBuilder, "OutputFolder");
chkWebMatrix.Bind(_modelBuilder, "UseWebMatrix");
tbNamespace.Bind(_modelBuilder, "ProjectNamespace");
tbDbClassName.Bind(_modelBuilder, "DbClassName");
In my example, _modelBuilder is a DataSet object and the properties shown ("ProjectConnection", "OutputFolder", etc) are simple string properties of the DataSet--not of records in the dataset, but of the dataset as a whole.
I'm not crazy about passing a property name as a string, and wonder if it's possible to re-write this function as a lambda, so it looks like this when called:
tbProjectConnection.Bind(property => _modelBuilder.ProjectConnection);
tbOutputFolder.Bind(property => _modelBuilder.OutputFolder);
I'm a novice with lambdas, so any help is much appreciated!
I don't think there is an easy way to do this, but there is a very interesting writeup at:
http://joelabrahamsson.com/getting-property-and-method-names-using-static-reflection-in-c/
This might give you what you are looking for, although it doesn't look simple.
Related
im completely new to the wcf service things so im a bit lost on the approach here. I have an operation in the service called GetHoldsJoined. The listbox im binding to is called lbxOpenHolds. I am able to set the result as an itemsource with the following:
public frmHoldsDashBoard()
{
InitializeComponent();
dbServiceClient db = new dbServiceClient();
db.GetHoldsJoinedCompleted +=new EventHandler<GetHoldsJoinedCompletedEventArgs>(db_GetHoldsJoinedCompleted);
db.GetHoldsJoinedAsync();
}
private void db_GetHoldsJoinedCompleted(object sender, GetHoldsJoinedCompletedEventArgs e)
{
lbxOpenHolds.ItemsSource = e.Result;
}
but what I want to do is set the selectedvaluepath to an attribute in one of the result list items. The result is a List collection. There is an attribute in each one of the list objects called a.HoldID, it is composite. I want this to be the selectedvalue member. How do I unbox this from GetHoldsCompletedEventArgs ?? Or is there some other way to do this?
Sorry if the question is asked kind of scatterbrained, I really didn't know how else to explain it.
What about something like this:
lbxOpenHolds.SelectedValuePath = "HoldID";
This should go right after setting the ItemsSource on lbxOpenHolds
Do folks have any guidance on when a simple .NET property that fires INotifyPropertyChanged.PropertyChanged is sufficient in a view model? Then when do you want to move up to a full blown dependency property? Or are the DPs intended primarily for views?
There are a few approaches:
1. The dependency property
While you using the dependency property it makes the most sense in elements-classes that have a visual appearance (UIElements).
Pros:
WPF do the logic stuff for you
Some mechanism like animation use only dependency property
'Fits' ViewModel style
Cons:
You need to derive form DependencyObject
A bit awkward for simple stuff
Sample:
public static class StoryBoardHelper
{
public static DependencyObject GetTarget(Timeline timeline)
{
if (timeline == null)
throw new ArgumentNullException("timeline");
return timeline.GetValue(TargetProperty) as DependencyObject;
}
public static void SetTarget(Timeline timeline, DependencyObject value)
{
if (timeline == null)
throw new ArgumentNullException("timeline");
timeline.SetValue(TargetProperty, value);
}
public static readonly DependencyProperty TargetProperty =
DependencyProperty.RegisterAttached(
"Target",
typeof(DependencyObject),
typeof(Timeline),
new PropertyMetadata(null, OnTargetPropertyChanged));
private static void OnTargetPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Storyboard.SetTarget(d as Timeline, e.NewValue as DependencyObject);
}
}
2. The System.ComponentModel.INotifyPropertyChanged
Usually, when creating a data object, you’ll use this approach. It is simple and neat solution for Data-like stuff.
Pros and Cons - complementary to 1. You need to to implement only one event (PropertyChanged).
Sample:
public class Student : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
PropertyChanged(this, e);
}
}
private string name;
public string Name;
{
get { return name; }
set {
name = value;
OnPropertyChanged(new PropertyChangedEventArgs("Name"));
}
}
3.PropertyNameChanged
Rising an event for each property with specified name(f.e. NameChanged). Event must have this name and it is up to you to handle/rise them. Similar approach as 2.
4. Get the binding
Using the FrameworkElement.GetBindingExpression() you can get the BindingExpression object
and call BindingExpression.UpdateTarget() to refresh.
First and second are the most likely depending what is your goal.
All in all, it is Visual vs Data.
As far as I know, DependencyProperty is only required when you need
PropertyValue inheritence
you need to allow the property to be set in Style setters
Use animation for the property
etc.
These features will not be available with normal properties.
DependencyProperty is required if you want to allow a binding to be set on the property. Usually this is for custom UIElements you create. You want to allow people to be able to bind data to your UIElements.
<local:MyUIElement MyProperty={Binding Path=SomethingToBindTo} />
To do this requires that MyProperty is a dependancy property
The main problem I see with INotifyPropertyChanged is if you viewmodel is complex containing many nested types it appears that you have to bubble the PropertyChanged event up through the hierarchy.
As the other answers have already said enough about when to create dependency property. i.e.
PropertyValue inheritence
you need to use binding on a property
Use animation for the property
The one more perspective/question on this is "In a WPF application is makes sense to create dependency properties in a control cause they are likely to change during user interaction like Height,width, text,content, background etc but what about other classes like Behaviors Classes(Non UI classes). Do properties in those classes need to be a dependency property?"
I won't say for very absolute or emphasis on some set of rules here but you should create your properties as DP. As from design perspective if a property is DP it's always in default form of WPF to use/bind.i.e.
As a DP is much more fast/natural in reflecting changes compare to a normal CLR property.
A DP has validation mechanism to validate the value assigned and a default structure to revert the value.
A DP has Coerce value callback to control the limits of property.
A DP has meta data associated with it unlike CLR property.
In terms of practices I've seen people doing many mistakes in nested bindings and then raising changes these kind of faults doesn't happen with a DP cause of it's design and compatibility of raising change itself. So with a little extra syntax you put a flexibility/performance/ easeness to your application. So go for it wherever affordable.
Still can't say sure for ViewModel classes/other helper classes. will update the answer if found convincing reasons in future.
Just a post worth reading on this topic
I'm very new to databinding, and so far have only had luck databinding to element properties in the GUI, or by binding to an ObservableCollection to display lists of data. Now I want to do something different.
I have a method that takes an index and returns a List of doubles, i.e.
List<double> GetValues( int index);
I have a GUI where the user selects the index from a combobox, and then several textboxes need to have their text updated with the values in the List. I actually have a thread running that caches all of this data, because I have UI elements in different places that consume and display the same information. So I figured, why not use databinding? The problem is, I have yet to find a good example online that explains how to take the index from the combobox, call the GetValues method, and then bind the resulting information to all of the textboxes -- all from XAML.
The closest article I've found is http://msdn.microsoft.com/en-us/magazine/cc163299.aspx. Most of the articles I've read talk about using the Source attribute, but then say, "well, the easiest way is to just use StaticResource, so we'll show you that method".
How can this be accomplished? Would it be advisable to just go back to the easy way of doing this entirely from code-behind?
The problem you're having is that you're trying to bind to the results from a function, and you may very well complicate things by trying to implement data-binding on something so simple from the code-behind. I'd recommend doing this from the code-behind.
That said, for the simplest and most useful approach, you need to have actual properties in your class to bind to, which you need to update when the index changes. Depending on how you pass the data around, this could reduce the code-behind, or just create more.
Here's an example of what you could end up with:
// Assume 1 of your textboxes displays a weight. Here's the property declaration:
// Disclaimer: Not compiled or tested at all.
public static readonly DependencyProperty WeightProperty = DependencyProperty.Register(
"Weight", typeof(double), typeof(MyClass), new PropertyMetadata(0.0));
public double Weight
{
get { return (double)this.GetValue(WeightProperty); }
set { this.SetValue(WeightProperty); }
}
// Here's an example of setting the property:
private void ComboBoxSelectedIndexChanged(object sender, RoutedEventArgs e)
{
List<double> values = myObject.GetValues(comboBox.SelectedIndex);
this.Weight = values[0];
}
// And in your XAML, assuming you've given your Window the name myWindow:
<TextBlock Text="{Binding ElementName=myWindow, Path=Weight}"/>
This can be useful if you plan on updating the Weight property in multiple places and want the TextBlock to always show the correct value.
On the other hand, if your properties will only update in the SelectedIndexChanged function and you don't need the values outside of that function, you may as well have just set the value yourself and reduce the unnecessary overhead:
private void ComboBoxSelectedIndexChanged(object sender, RoutedEventArgs e)
{
List<double> values = myObject.GetValues(comboBox.SelectedIndex);
txtWeight.Text = values[0].ToString();
}
I noticed that ObservableCollection in WPF reflects changes in GUI only by adding or removing an item in the list, but not by editing it.
That means that I have to write my custom class MyObservableCollection instead.
What is the reason for this behaviour?
Thanks
The ObservableCollection has no way of knowing if you make changes to the objects it contains - if you want to be notified when those objects change then you have to make those objects observable as well (for example by having those objects implement INotifyPropertyChanged)
another way of achieving this would be that you implement a new XXXViewModel class that derives from DependencyObject and you put this one in the ObservableCollection.
for this look at this very good MVVM introduction: http://blog.lab49.com/archives/2650
an example for such a class would be:
public class EntryViewModel : DependencyObject
{
private Entry _entry;
public EntryViewModel(Entry e)
{
_entry = e;
SetProperties(e);
}
private void SetProperties(Entry value)
{
this.Id = value.Id;
this.Title = value.Title;
this.CreationTimestamp = value.CreationTimestamp;
this.LastUpdateTimestamp = value.LastUpdateTimestamp;
this.Flag = value.Flag;
this.Body = value.Body;
}
public Entry Entry
{
get {
SyncBackProperties();
return this._entry;
}
}
public Int64 Id
{
get { return (Int64)GetValue(IdProperty); }
set { SetValue(IdProperty, value); }
}
// Using a DependencyProperty as the backing store for Id. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IdProperty =
DependencyProperty.Register("Id", typeof(Int64), typeof(EntryViewModel), new UIPropertyMetadata(new Int64()));
}}
important things here:
- it derives from DependencyObject
- it operates with DependencyProperties to support WPFs databinding
br
sargola
You can register a method in the view model class aginst the PropertyChanged event of data class objects and listen to them in View model when any change in the property of the data objects happen. This is very easy and straight way to have the control in View model when the items of an observable collection changes. Hope this helps...
Probably because items have no way to alert the collection when they are edited - i.e. they might not be observable. Other classes would have similar behavior - no way to alert you to a every change in the graph of referenced classes.
As a work-around, you could extract the object from the collection and then reinsert it after you are done processing. Depending on your requirements and concurrency model, this could just make the program ugly, though. This is a quick hack, and not suitable for anything that requires quality.
Instead, you could implement the collection with an update method that specifically triggers the ContentChanged (not sure about the name) event. It's not pretty, but it is at least quite easy to deal with.
Ideally, as kragen2uk says, it would be best to make the objects observable and keep your client code clean and simple.
see also this question.
I am trying to use databinding to bind data to a Silverlight toolkit chart.
I will have one to many sets of series so cannot determine how many series i need before hand.
I also want to stick to a databinding model and not resort to programmatically adding these series as many other controls bind to this datasource.
I found an article on the web by Jeremiah Morrill that showed a solution for this very problem.
Jeremiah's solution
Now this worked perfectly at first, until I tried to update my databinding's datasource values while the application was running, and this would not reflect. As if it was not subscribed to the PropertyChanged event.
I even bound the same data to a datagrid next to the chart, and the datagrid reacts as expected changing everytime my databinding's datasource values change.
In my ChartHelper from Jeremiah's solution, i have the following dependency property
public static readonly DependencyProperty SeriesSourceProperty =
DependencyProperty.RegisterAttached("SeriesSource",
typeof(IEnumerable),
typeof(ChartHelper),
new PropertyMetadata(SeriesSourceChanged));
The SeriesSourceChanged event is called when my application starts up.
However, when my DataBinding's datasource values change, this is not called again.
So questions are as follows:
How can I capture the PropertyChanged notification with this solution?
Is there something I can add to the DependencyProperty above to capture this?
Is it something i need to add to the chart or series to achieve this?
I have been racking my brain over this for several days, so any help or suggestions will be much appreciated
Thanks!
The SeriesSource type should be ObservableCollection instead of IEnumerable. Then you do something like this:
private static void SeriesSourceChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
var sender = o as YourType;
var newCollection = e.NewValue as ObservableCollection<DataSetViewModel>;
if (newCollection != null)
{
newCollection.CollectionChanged += new NotifyCollectionChangedEventHandler(sender.OnCollectionChanged);
}
}
private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
}
I never did find a solution to this problem and ended up using a chart control from visifire
I found this much easier to customise but never found a neat way of using databinding to achieve this and ended up with a more programattic approach.