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!
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 wpf form which contains a datagrid. I did put a button on my form to "Refresh" the datagrid. Steps I'm trying to get it to refresh:
I update the viewsource from my db:
SupportCaseViewSource.Source = SupportCaseManager.GetAllSupportCases();
I refresh the datagrid items:
SupportCaseDataGrid.Items.Refresh();
But nothing happens...no new data displayed!!
Has someone an idea how to do this?
Thanks
Beat
Rather than manually instructing your controls to refresh, you can implement INotifyPropertyChanged and call PropertyChanged with appropriate arguments. In your case this is probably
PropertyChanged(this, new PropertyChangedEventArgs("Source"));
It'll be whatever is bound to the SupportCaseDataGrid.ItemsSource.
I'm using a DataGrid in my silverlight application to display some data that's refreshed on a timer. My problem is that when this happens the vertical scrollbar in the grid resets to the top, whereas I want it to stay in the same position. Does anyone know how I can make this happen?
I've tried overriding the ItemsSource property on the grid to store the vertical scroll position and then reset it, but this only affects the scrollbar and doesn't force the correct rows to be displayed. Is there a way to force this behaviour?
Here is a similar question about Setting the scroll bar position on a ListBox
After rebinding Silverlight Listbox control how do you get it listbox to scroll to back to the top?
Since the DataGrid also supports a ScrollIntoView method, you should be able to use a similar technique such as
theDataGrid.ItemsSource = data;
theDataGrid.UpdateLayout();
theDataGrid.ScrollIntoView(theDataGrid.SelectedItem, theDataGrid.Columns[0]);
I couldn't find a decent answer last time I looked. I wanted to keep the current element selected in the grid but that wouldn't work on an ICollectionView refresh (I use MVVM and get automatic updates from the server).
ScrollIntoView() was not an option for me because the currently selected item may NOT be in view. Having the CurrentChanged event firing out of control was also quite a bother.
In the end, I used the Infragistics grid and it does just that out of the box. Problem solved for me.
You may have a look at the DevExpress free grid. I think it had the same nice behaviour (I tested it but I can't remember the outcome).
You could try setting the SelectedItem thro the UI thread, so that the UI can refresh itself,
like so
private void Button_Click(object sender, RoutedEventArgs e)
{
Person p = new Person() { Name="sss",Age=11}; //datagird's itemsSource is Collection<person>
people.Add(p);
dg.SelectedItem = p; //dg is my datagrid name
Dispatcher.BeginInvoke(() => { dg.SelectedItem = p; });
}
Im assuming that new rows are loaded thro the ViewModel, so thats why it makes sense to place the BeginInvoke there. Since the ViewModel operations run on a different thread, and just setting the SelectedItem on its own might not work, this has worked for someone else
I've also had issues with this. I solved it by remembering the item I want to scroll to, then re-binding the DataGrid. I handle the LayoutUpdated event in order to implement the desired functionality:
void MyDataGrid_LayoutUpdated(object sender, EventArgs e)
{
// Reference the data item in the list you want to scroll to.
object dataItem = yourDataItem;
// Make sure the item is not null and didn't already scroll to the item.
if (dataItem != null && this.dataItemScrolledTo != dataItem)
{
// Remember the item scrolled to.
this.dataItemScrolledTo = dataItem;
// Scroll datagrid to the desired item.
MyDataGrid.ScrollIntoView(dataItem, MyDataGrid.Columns[0]);
}
}
I've modified CodeMaster's solution so that you don't need a class level variable. Put this code in the method that updates the ItemsSource. It will dynamically create the eventhandler, attach it, then detach it.
EventHandler MyDataGrid_LayoutUpdated = null;
MyDataGrid_LayoutUpdated = (s, e) =>
{
MyDataGrid.ScrollIntoView(dataItem, MyDataGrid.Columns[0]);
MyDataGrid.LayoutUpdated -= MyDataGrid_LayoutUpdated;
};
MyDataGrid.LayoutUpdated += MyDataGrid_LayoutUpdated;
I have a multi-language silverlight application where the resources are stored in resx files for different languages and bound to the buttons' and labels' Content Properties inside the xaml.
When setting the thread's UI culture in the constructor of the silverlight's page every thing works fine, but when changing it based on user's selection (through combobox selection)
the interface doesn't change. I need the page to redraw the controls and rebind to the resource files based on the new thread's UI culture.
I am not sure what mechanism you are using to bind your view to your localization repository, but I am guessing that the problem lies with notification.
The view will only update the data in a binding when it gets a notification event. Most likely, the object with the localization data that you are binding to is not sending notifications when the culture changes.
You might consider adding an INotifyPropertyChanged to the object that holds your localization strings. Then, add a method to that class called "NotifyThatEverythingChanged". In that method, just send that the property string.Empty has changed, which tells the UI to update everything in the data context.
In my case, I have the object that the RESX auto-generated for me called MyUIStrings. It has a bunch of static strings in it. I derive from that class, and add the functionality to notify that everything has changed. The UI will act accordingly:
public class NotifyableUIStrings : MyUIStrings, INotifyPropertyChanged
{
public void NotifyThatEverythingChanged()
{
OnPropertyChanged(string.Empty);
}
protected void OnPropertyChanged(string propertyName)
{
var handlers = PropertyChanged;
if(handlers != null)
handlers(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
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.