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.
Related
This is a similar question to this one, but I'm hoping that a better answer has come along in the six years since it was asked.
I have a custom dictionary that I want to use in all textboxes in the application. I don't seem to be able to set the SpellCheck.CustomDictionaries property in a style, like I can with the SpellCheck.IsEnabled property, and I don't want to have to add the setter to every textbox individually.
The answer posted in that question requires hooking in to the Loaded event of every window where you want to use the custom dictionary. We have a large application that is growing all the time, and do not want to have to add handlers for every window, as well as rely on developers remembering to add the code when they add a new window.
Is there any better way to specify a custom dictionary for the whole application? Thanks.
Probably not what you wanted, but I used this EventManager.RegisterClassHandler to handle all of certain type's certain event.
For ex, here I am registering to all TextBoxes' LoadedEvent in MainWindow's constructor:
EventManager.RegisterClassHandler(typeof(TextBox), FrameworkElement.LoadedEvent, new RoutedEventHandler(SetCustomDictionary), true);
and define the RoutedEventHandler:
private void SetCustomDictionary(object sender, RoutedEventArgs e)
{
var textBox = e.OriginalSource as TextBox;
if (textBox != null)
{
textBox.SpellCheck.IsEnabled = true;
Uri uri = new Uri("pack://application:,,,/MyCustom.lex");
if (!textBox.SpellCheck.CustomDictionaries.Contains(uri))
textBox.SpellCheck.CustomDictionaries.Add(uri);
}
}
I have a custom control in the early stages of development as I endeavour to learn about wpf custom control development. The custom control inherits from ItemsControls which gives me access to an ItemsSource property to which I am binding an enumerable collection.
Currently I have a simple two project solution comprising my custom control in one and a test project in the other to test the former. In my test project I have a simple mainwindow onto which I have put my custom control and bound its ItemsSource.
<WpfControls:VtlDataNavigator x:Name="MyDataNavigator"
ItemsSource="{Binding ElementName=MainWindow, Path=Orders}" />
In the loaded event of the main window (which implements INotifyPropertyChanged) I instantiate the Orders collection. The customcontrols gets initialised before the main window loads but I can see from examining the Live Visual Tree in visual studio that once the main form loads the custom controls Items Source property is indeed set to Orders. Now of course I'd actually like to count the orders and have my custom control display that (it's a simple data navigator so what I'm after is the record count). I know how to get the count but how do I know when the itemsSource has changed so that I can react to it and get the count. There's no itemsSourceChanged event that I can see.
I've seen this blog article, but I'm wondering if there is a more straightforward approach to this as it seems such an obvious thing to want to know about.
You can do that using OverrideMetaData.
Try this:
public class Class1 : ItemsControl
{
static Class1()
{
ItemsSourceProperty.OverrideMetadata(typeof(Class1),
new FrameworkPropertyMetadata(null, OnItemSourceChanged));
}
private static void OnItemSourceChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
Debug.WriteLine("Why you haz Changed me!");
}
}
The ItemsSource is a DependencyProperty, and when creating DPs you can optionally specify a "property changed" event. Unfortunately ItemsSource is locked away in the base class, so I started wondering if there might be a way to add your own event to an existing DP. I came across this article that looks promising. Basically you would do something like this (untested so read the article!):-
var dpd = DependencyPropertyDescriptor.FromProperty(
VtlDataNavigator.ItemsSourceProperty,
typeof(VtlDataNavigator));
if (dpd != null)
{
dpd.AddValueChanged(
vtlDataNavigatorInstance,
delegate
{
var count = VtlDataNavigatorInstance.ItemsSource.Count; // Or whatever...
});
}
I databind the LineGraph with a datasource when new points comes from backend, the problem is that the grid isnt refreshed, you can do a plotter.FitToView() to get it to refresh but that also fits the new graph to the plotter window this is very irretating if you have zoomed in and panned to a specific point on the chart because it will zooom out to fit the graph on the chart... So, is there a way to refresh it after databind (You think that a databind would refresh it+..
I can also consider changing WPF chart enterily i have one requirement and its that you can define draggable points on the chart
The best way that I have found to do this, is to have a Property in your code behind that represents the DataSource and bind the chart's DataSource to that property. Have your code behind implement INotifyPropertyChanged and call OnPropertyChanged every time you update or re-assign your data source. This will force the plotter to observe the binding and redraw your graph.
Example:
EnumerableDataSource<Point> m_d3DataSource;
public EnumerableDataSource<Point> D3DataSource {
get {
return m_d3DataSource;
}
set {
//you can set your mapping inside the set block as well
m_d3DataSource = value;
OnPropertyChanged("D3DataSource");
}
}
protected void OnPropertyChanged(PropertyChangedEventArgs e) {
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) {
handler(this, e);
}
}
protected void OnPropertyChanged(string propertyName) {
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
The interface to the WPF D3 chart is entirely programmatic, i.e. you have to 'push' updates rather than use binding to automatically refresh the UI. As an alternative perhaps consider Visiblox chart, there is a blog post here which describes how to make datapoints draggable as you require:
http://www.visiblox.com/blog/2011/11/creating-a-custom-behaviour-part-3-the-finale
Disclosure: I work for the company that created Visiblox charts.
Have you tried reassigning the data collection when you add new data? I noticed this was necessary to update my graph. For example, after adding new objects to my collection, I'd use this:
DataCollection = new ObservableCollection<DataObject>(DataCollection);
This started working, and I thought it was because the chart only responded to OnPropertyChanged and not OnCollectionChanged, or something to that effect. The line is painfully pointless and slows down the display for large amounts of data, though.
Edit: This is including Jason's answer above to notify of changes!
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();
}
Which event fires when DataGrid's source is updating? I've tried DataContextChanged and SourceUpdated but it never worked out.
Actually I need a simple thing. I want, if there is a new row comes, scroll the GridView's scrollbar down to the bottom to see what it was.
I had the same problem and I manage it this way
DataGrid myGrid = new DataGrid();
CollectionView myCollectionView = (CollectionView)CollectionViewSource.GetDefaultView(myGrid.Items);
((INotifyCollectionChanged)myCollectionView).CollectionChanged += new NotifyCollectionChangedEventHandler(DataGrid_CollectionChanged);
You then need to implement the logic in the event handler DataGrid_CollectionChanged.
Set NotifyOnTargetUpdated = true for the ItemsSource binding and handle TargetUpdated event. If you've multiple bindings, then look for DataTransferEventArgs Property to find out if the target is ItemsSource or not.
If you are trying to have the grid refresh when something is added to the database itself, that's not going to happen. I'm more familiar with WinForms than WPF but I'm assuming there is no magical way to keep a grid in sync with the database without writing some background process that continuously checks for database changes.
If you are updating the actual data source of the grid (ex. Collection) then that will update the grid.
For my part i've used SelectionChange notification which raise each event Del/Add/Edit/Select
It's work very well
private void dataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Console.WriteLine("hi");
}