Conversation
|
FormsPlot and WpfPlot now both show plots at design time. If there is a problem with wpf.mp4 |
Add method to gently crash if there is a problem with System.Drawing.Common rendering and return a text error message #1048
|
I added a render test inside a try/catch block that should identify render errors and display them as text in the control at design time ScottPlot/src/ScottPlot/Drawing/GDI.cs Lines 21 to 47 in 382e985 |
|
WpfPlot and FormsPlot now do this as the first thing in their initializers: string renderErrorMessage = ScottPlot.Drawing.GDI.DrawingTest();
if (renderErrorMessage != null)
{
InitializeComponent();
/* display the error message in a textbox */
return;
}@bclehmann do you think this is worth adding to AvaPlot? |
| byte[] bytes = stream.ToArray(); | ||
| int expectedBitmapSize = 454; | ||
| if (bytes.Length != expectedBitmapSize) | ||
| throw new InvalidOperationException($"test image was {bytes.Length} bytes (expected {expectedBitmapSize})"); |
There was a problem hiding this comment.
Throwing something in order to immediately catch it is something of an antipattern. It's using exception handling as flow control instead of an if/else.
This method should probably either return a boolean to indicate success/failure, or just let any exceptions bubble up to the caller.
If the actual error message is important then it should throw an exception which is caught by the caller and the error message surfaced to the user. Alternatively, you can return false to indicate failure and then set an error field somewhere (like in many C APIs), or return a struct with a success field set to false and some extra information (like in many AJAX libraries).
I don't normally like the C way of doing things because it's used everywhere to get around the lack of exception support, however it does have some benefits:
- It does not obligate the caller to handle any exceptions
- Thus it's a pattern often used in AJAX when it doesn't matter if the request fails (or when failures are already handled by some middleware which will retry)
- Performance and compatibility with embedded systems (not really a consideration here)
There was a problem hiding this comment.
Returning a struct like this would probably be the best option, provided you don't want to let the exception bubble up to the caller. That choice depends on whether you think the caller ought to be obligated to handle the issue or die.
struct TestResult {
bool success;
string errorMessage;
}
Yeah, I think it looks easy and helpful for a lot of users. I don't really like how |
Hey @bclehmann, I'm a bit confused by your objection/suggestion. Could you rephrase your concern or proposed solution to help me understand it better? My intent is that I could move Interested in your feedback! |
I had two concerns, the first was the throw on line 39 which looked like it was using try/catch as a control structure, but the catch can actually catch multiple issues so my conclusion was too hasty. One could argue about it as a matter of taste, but now that I have thought about it I think it's probably the better solution. The other was how the function indicates the design-time exception. I think returning a string with an error message is counter-intuitive. The name My preferred solution is just to change the return type to void and remove the catch statement. The caller catches any exceptions and displays the error message. However, I think returning a boolean (or a struct with a boolean success field) is more appropriate for a method with the word "Test" in its name.
I like this idea, but I think there is a benefit to keeping it in GDI, since moving to a different graphics library would require this to be rewritten. I like the current state where nothing (that I know of) in the Control namespace is dependent on System.Drawing.Common. |
|
You can see what I meant in #1052. I don't know how well I communicated my concerns. |
I'm sold! A try/catch block in the initializer of each control is a lot more straightforward, and a better design. Thanks for expanding on your thoughts/suggestions! I'll work in #1052 to test the AvaPlot and also add similar try/catch blocks to the other controls 👍 EDIT: lol this came around full circle... if we are try/catching in controls, we can just test against if (DesignerProperties.GetIsInDesignMode(this))
{
try
{
Plot.Title($"ScottPlot {Plot.Version}");
Plot.Render();
}
catch (Exception e)
{
InitializeComponent();
PlotImage.Visibility = System.Windows.Visibility.Hidden;
ErrorLabel.Text = e.ToString();
return;
}
} |

addresses #1043