This thread looks to be a little on the old side and therefore may no longer be relevant. Please see if there is a newer thread on the subject and ensure you're using the most recent build of any software if your question regards a particular product.
This thread has been locked and is no longer accepting new posts, if you have a question regarding this topic please email us at support@mindscape.co.nz
|
We are using your WPF Chart control. We have the situation where we display different plots on different windows. We would like to provide the user with the ability to zoom into one plot. Then allow them to navigate to a different window. Then return to the window with the plot and see the plot in the zoomed state they left it in when the window was closed (i.e. persist the zoom state). We are using a viewmodel which binds to the chart axis properties (Minimum, Maximum, ActualMinimum, ActualMaximum). We are trying to set these values when the window opens to the values we had when the window closed but it does not seem to work. Do you have any suggestions how we can accomplish this? Is there a zoom property we can set to accomplish this? |
|
|
Hello, This is a known problem that is caused by these 4 properties being highly constrained - ActualMaximum can not be larger than Maximum, ActualMinimum can not be larger than ActualMaximum and so on. This means that the properties need to be set in the correct order so that the constraints don't interfere with the values that you want to set. The problem this causes is that when binding these values to the ViewModel, even if you set the properties in the correct order in the model, the bindings will be resolved in their own order meaning you don't really have control here. The approach that we recommend here is to set the properties in code. Of course to stick with the MVVM pattern as much as possible, the best thing to do is encapsulate this logic into an attached property: Create a new class to hold those 4 properties, for example "Viewport". Create an Attached property of that type to be set on a ChartAxis. In the property changed callback, set the 4 properties to the ChartAxis in this order: Maximum, Minimum, ActualMaximum, ActualMinimum. In your ViewModel, create a property to return an instance of Viewport. When you change one of those 4 properties in your model, make sure the Viewport object is updated and raise a property changed notification. On each ChartAxis, set the attached property to be a binding to your Viewport property on the ViewModel. And make sure you no longer set those 4 ChartAxis property bindings. We are considering possible ways to fix this in the ChartAxis such as providing this single Viewport property on the ChartAxis, or somehow applying the constraints after bindings have been resolved, but we don't have a timeframe of when this will be resolved. Please let me know if you have questions about this approach. -Jason Fauchelle |
|
|
we have same problem and we have already tried the attached properties you suggested a long time ago, but it does not work at all, especially when the axis values are strings. Thanks, Gordon |
|
|
Even though not many customer ask this feature, is that possible for you guys to implement/improve it in the near future? |
|
|
Hello, I still haven't been able to make it work using your suggested attached property. It actually makes things slower in updating the plot. It would really help out if this feature was made available. Thanks Oscar |
|
|
Hi Gordon and Oscar, I will look at providing a solution to this within the next 2 weeks. -Jason Fauchelle |
|
|
That would be awesome. It would be quite beneficial for my team as well. The proposed method did not work particularly well for us. |
|
|
Hi evilbyte and Gordon, I remember reproducing this issue a long time ago, but I'm no longer able to do so. When I bind the 4 values of the ChartAxis to properties on the model with a TwoWay binding, the viewport of the axis behaves as expected. I have attached a minimal repro project for you to try out. To run this, make sure to include a reference to your copy of WPF Elements. The demo includes a tab control containing a chart. Zoom into the chart, then switch to the other tab which causes the chart to be unloaded. When you switch back to the Chart tab, you'll see the Chart maintains the zoom due to the bindings. If you go to MainWindow.xaml and remove all the bindings on the ChartAxis, then run the app again, you'll find the viewport resets every time the Chart tab is focussed. Please have a go at modifying this sample to reproduce the problems you're seeing, then send it back to me and I'll look into it further. -Jason Fauchelle |
|
|
Hi Jason, Oscar will contact you soon. Since he is the one talked to you a very long time ago with this problem. for the simple plot, it is working. When you have quite a few curves and with the axis value as string or DateTime, it will have a problem. Thanks, Gordon |
|
|
Hi Jason, The zoom seems to work for a set of curves where the x and y are double values. The other case we are interested in is Bar type chart (i.e. Tornado, Histogram) where we zoom in. In this case one axis has strings and the other double values. I've been working on creating a demo project for you but still having some issue creating a demo project with the setup we have in our application. In the mean time I tried to use your demo projects. Specifically the Negative Bars and the Histogram. However I cannot get these plots to zoom by doing the drag with the mouse. I set the zoommode to be "Both" but nothing happens. What am I missing? Also how would you set the ActualMinimum and ActualMaximum for the case where the axis are strings? Thanks Oscar |
|
|
Hi Oscar, Thanks for the additional information. I have attached an update of my repro app so that the chart is now displaying strings along the X axis. As you will see, it still works as expected when switching between tabs. This only works due to the ActualMinumum and ActualMaximum bindings, as removing these will cause the zoom to reset when switching tabs. When using strings or other objects (but not DateTime) along an axis, I would recommend setting all the properties to be numbers as you'll see in the repro. The numbers that you want are simply the index of the objects in your collection. This is especially required for ActualMinimum and ActualMaximum because zooming and panning can cause the viewport to be anywhere between objects which can only be represented by numbers rather than the objects themselves. Hope the repro project helps out. Let me know if you are still able to send me a repro project (or modified version of my one) that demonstrates binding the 4 viewport properties not working. -Jason Fauchelle |
|
|
Hi Jason, Thank you for your project. It's very helpful. I have modified your project to try and show what we are trying to do.
What we are looking for is the ability to apply a saved zoom state and get back the chart in the zoom state we had. (We would like to get step 5 working) Eventually make it work for ZoomMode="Both". Right now this example only has ZoomMode="Horizontal". Thanks Oscar |
|
|
Hi Oscar, Thanks for spending the time to update my repro project. The reason why it doesn't work is because the names of the properties in ViewModel have been changed, but the strings within the OnPropertyChanged calls have not been updated. When I updated all the OnPropertyChanged calls within each property to match the property names, all three buttons seem to work as I'd expected. Try this out and let me know if it works as you'd expect too. Could this also be the cause of the issue within your app? If not, please update the repro project to match the issue in your application and I'll look into it further for you. -Jason Fauchelle |
|
|
Hi Jason, Yes I guess setting the correct property names for the NotifyPropertyChange would help. :) Thanks! I changed it to the correct string property names and it worked. However I finally managed to create a repro-project with our code and it doesn't work in our case. I have directly sent you a copy of the repro-project for our application. Thanks Oscar |
|
|
Thanks for sending the repro project Oscar, When I clicked the "Save Zoom" button, the breakpoint you set in UpdateViewPortBounds gets hit, and looking into the properties of viewModelViewPortBounds, the YAxisActualMin and YAxisActualMax values were both empty strings. The means the viewport of the Y axis was never being property saved which is why trying to restore the viewport didn't work. The reason they were empty strings comes from the StringAxisValueConverter. Whenever a value is not a string, you were returning 0, and whenever a value is not an integer, you were returning empty string. Fortunately this is easy to fix. As I mentioned previously, when you zoom on a string axis, the actual min and actual max will generally not land on an exact string - instead it will sit between 2 values which is best represented as a number. So I'd recommend you update the StringAxisValueConverter to also support numbers. In GetAxisPlotPosition, after the first null check, add:
In GetDataObjectAt, instead of returning empty string, return d. When you now save the zoom, you'll see that actual min and actual max for the Y axis can be saved correctly - most likely as numbers. Now when you hit "Apply Zoom" it will work correctly. "ReLoad With Zoom" on the other hand may still be broken. I've found this is due to the DualSlider instances hidden within each axis. When the chart is recreated, new DualSliders are created with their own default viewport settings which get bound to the chart axis viewport values. Unfortunately those bindings are being resolved after your own bindings and so are overwriting the viewport of the Y axis to 0-1. Fortunately, (if you do need the ReLoad With Zoom scenario in your app) there are a couple of quick fixes for this that you can try right now. The fastest way to fix this is to go to your ReloadPlotWithZoom method, and wrap the call to ApplyZoom within a Dispatcher like this:
Personally I try to avoid Dispatchers where possible, but this worked extremely well in your repro project. A better solution that will take a bit more work would be to create your own ChartAxis style/template. This can be a copy of our generic style and simply remove the DualSliders. This of course is only really an option if you don't ever display the built in dual sliders in your app. Taking this approach has the added benefit of slightly improving the performance of your charts. Hope that helps, let me know if you have further questions. -Jason Fauchelle |
|
|
Hi Jason, I modified the converter as follows: public double GetAxisPlotPosition(object o) { if( o == null ) { return 0; }
But it doesn't seem to work. Did it work for you? Did I change the code incorrectly? Please see the attachment (SuggestedChanges.docx). When you zoom in you get tick marks with numbers (see first image). Or worse yet the string with the names disappear completely (see second image). If I remove the converter I get the correct results (DesiredResults.docx). However Gordon mentioned that a long time ago you suggested putting in the converter to deal with other issues in other plot types. So maybe removing the converter is not an option. As to the applying the zoom scenario we do need "ReLoad With Zoom" for our app. We do not want to go the Dispatcher route because (from Gordon's experience) our plot scenarios get more complicated and this approach is found to be unreliable. Sometimes it works other times it doesn't. We also would like to avoid having our own control template because in the future if there are any changes which Mindscape does things may stop working on our end and may be hard to track down. Would it be possible you to provide a property on the Chart which when set would remove the DualSliders. Because of where we are in our development cycle, we would prefer not to do a quick fix and wait for it to be fixed on your end. Thanks Oscar |
|
|
Hi Oscar, Yes your changes are correct, and these changes did solve the problem for me in your repro project. Gordon is right, you're best to keep that converter so that you have full control of how your data is displayed along the axis. Regarding the numbers appearing on the axis, this is a different issue altogether. Did you try zooming far into the chart before making the changes to the converter? You may find that before changing the converter, "0" appears in the axis - so isn't related to the changes. To avoid this, you'll simply want to set AllowMajorTiackSpacingZoomAdjustment to false so that the MajorTickSpacing option is used at all zoom levels, rather than being scaled. Does that solve this new issue for you? Regarding the dual sliders in the chart axis, I can certainly look at removing them from our template when they are not visible. I should be able to get this done in 2 weeks. Let me know if you have further questions about the zoom saving. -Jason Facuehlle |
|
|
Thanks Jason. Setting the AllowMajorTickSpacingZoomAdjustment to false worked. I think we are very close to what we are looking for with respect to zoom saving. I will do a test with DateTime axis and see if that is okay. Thank you very much Jason. That will be great once you modify the dual slider related code. Please let us know when you do. ... Oscar |
|
|
Hi Jason, FYI. Just so you are aware there is a similar zoom issue (i.e. ReLoad With Zoom scenario) when using the DateTime axis as with the String axis. Let me know if you need a repro-project. Thanks Oscar |
|
|
Hi Oscar, Splitting the axis into two templates - one with sliders and one without - worked out well. This fix will be available in the next nightly build. When you get it, the string-based axis repro that you sent will work now. Of course the "reload with zoom" problem will be still present if you do enable the sliders. Your datetime-axis repro suffers from an additional problem, but I was able to solve this in your repro quite easily. The issue is that all the viewport properties are set before the ValueConverter is set. Without the converter, the axis isn't able to create the date time scale correctly. To solve this, I went to your WpfMsChart.SetAxisProperty and moved the block of if-statements that sets the ValueConverter to be at the top of the method. (Anywhere above where the viewport properties are set will be fine. I hope this solution is fine with you. Let me know how it goes. -Jason Fauchelle |
|
|
Hi Jason, I tried the latest nightly build in the repro-project and the "reload with zoom" is working. I also change the location for the block of if-statements and the "reload with zoom" also works with the datetime-axis. Thank you very much Jason. Oscar |
|
|
Hi Jason, Finally I found some time to test the zooming stuff. The only problem for the DateTime axis: if we just set ActualMax without set the ActualMin, it will automatically set the ActualMin to 0001/01/01 If we set ActualMin without set ActualMax, it will set both to 0. If we set both then it seemed ok. We donwload June 03, 2015 Nightly build. |
|
|
Hi Gordon, Solving this is proving to be difficult. For now I'm going to leave this, and recommend that you set both ActualMin and ActualMax. If ActualMax is unknown, just set it to Maximum (Same with ActualMin). Sorry I couldn't help further. -Jason Fauchelle |
|