Add Render event and workaround
This discussion was imported from CodePlex
GeertvanHorrik wrote at 2014-03-26 16:22:
Hi,
Today I was trying to resize the plot to a specific size. The reason is that we need to align the actual plot without axes to a specific size. Unfortunately the sizes cannot be specified (only for the whole control).
I tried to get an event when the plot is being drawn (because I need the PlotArea to have valid values), but there are no events on the PlotModel class.
Below is a workaround which works great:
Today I was trying to resize the plot to a specific size. The reason is that we need to align the actual plot without axes to a specific size. Unfortunately the sizes cannot be specified (only for the whole control).
I tried to get an event when the plot is being drawn (because I need the PlotArea to have valid values), but there are no events on the PlotModel class.
Below is a workaround which works great:
public static class OxyPlotExtensions
{
private class RenderAnnotation : Annotation
{
public event EventHandler<EventArgs> Rendered;
public override void Render(IRenderContext rc, PlotModel model)
{
base.Render(rc, model);
Rendered.SafeInvoke(this);
}
}
public static void AddRenderHandler(this PlotModel plotModel, EventHandler<EventArgs> handler)
{
Argument.IsNotNull(() => plotModel);
Argument.IsNotNull(() => handler);
var renderAnnotation = EnsureRenderAnnotation(plotModel);
renderAnnotation.Rendered += handler;
}
public static void RemoveRenderHandler(this PlotModel plotModel, EventHandler<EventArgs> handler)
{
Argument.IsNotNull(() => plotModel);
Argument.IsNotNull(() => handler);
var renderAnnotation = EnsureRenderAnnotation(plotModel);
renderAnnotation.Rendered -= handler;
}
private static RenderAnnotation EnsureRenderAnnotation(PlotModel plotModel)
{
var annotation = plotModel.Annotations.FirstOrDefault(x => x is RenderAnnotation);
if (annotation == null)
{
annotation = new RenderAnnotation();
plotModel.Annotations.Add(annotation);
}
return (RenderAnnotation)annotation;
}
}
Maybe you can add the Render event to the PlotModel so everyone can do something when the plot is being rendered?tibel wrote at 2014-03-26 19:20:
Rendering does belong to the control not to the model.
GeertvanHorrik wrote at 2014-03-26 19:42:
I fully agree. But then why is there a PlotArea on the model? And although the render itself is not part of the model, it would be very nice if I could at least be notified when the model is being rendered by the control.
objo wrote at 2014-03-26 20:45:
Did you try setting the
It is easy to add Rendering/Rendered events to the
The
Width
, Height
, AutoAdjustPlotMargins
and
PlotMargins
of the Plot
control? If you do this, I think the size of the plot should be fixed.It is easy to add Rendering/Rendered events to the
PlotModel
, but I would like to avoid it if it is not really needed.The
PlotModel
was meant to be the abstraction of the plot view - so it contains both the "plot area" and all the transforms that are related to the size of the view. See also
https://oxyplot.codeplex.com/workitem/10133 which is related to this.GeertvanHorrik wrote at 2014-03-26 20:51:
What I did was to use the Padding of the PlotModel to make sure that the plotarea itself always has a fixed size. Below is the code that allows a developer to make the width of the PlotArea (thus the plot itself can be larger) exactly the size
of RealPlotWidth.
private void UpdatePlotArea(int dispatchCounter = 0)
{
if (!plot.IsVisible)
{
return;
}
var plotWidth = plot.ActualWidth;
if (plotWidth == 0d)
{
return;
}
var plotModel = plot.Model;
if (plotModel == null)
{
return;
}
if (plotModel.PlotArea.Width == 0d)
{
if (dispatchCounter < 5)
{
Dispatcher.BeginInvoke(() => UpdatePlotArea(dispatchCounter + 1));
}
return;
}
// Magic constants we need to fix the left and right margins of Oxyplot
const int RightPadding = 5;
const int DefaultOxyplotPadding = 8;
var axisWidth = plotModel.PlotArea.Left - plotModel.PlotAndAxisArea.Left + DefaultOxyplotPadding;
var leftPadding = plot.ActualWidth - RealPlotWidth - axisWidth - DefaultOxyplotPadding;
if (leftPadding < 50)
{
// Exit, issue with redrawing
return;
}
var padding = new OxyThickness(leftPadding, 0, RightPadding + DefaultOxyplotPadding, 0);
if (AreEqualOxyThickness(padding, plotModel.Padding))
{
return;
}
plotModel.Padding = padding;
plotModel.InvalidatePlot(false);
}
private static bool AreEqualOxyThickness(OxyThickness oxyThickness1, OxyThickness oxyThickness2)
{
if (oxyThickness1.Left != oxyThickness2.Left)
{
return false;
}
if (oxyThickness1.Top != oxyThickness2.Top)
{
return false;
}
if (oxyThickness1.Right != oxyThickness2.Right)
{
return false;
}
if (oxyThickness1.Bottom != oxyThickness2.Bottom)
{
return false;
}
return true;
}
bvsms wrote at 2014-03-27 01:14:
objo wrote:
For example a plot will display a line series with data that can vary fro 0 to 1000000.
Let's assume we fix the plot width. If the data is within the range 0-10 then the x-axis width will have a certain value. However if we load data in the range between 10000 -100000 then the x-axis width will shrink to accommodate the extra digits displayed on the Y-axis.
It gets even worse if we enable the Y-axis title. (the x-axis shrinks even more.)
In other words rather than fixing the plot width, we need a way of fixing the x-axis width and allow the plot width to move dynamically. Ideally it would be great to anchor the origin of the x-axis as well.
If this is not possible, then having a "rendered" event would allow us to do all the calculations manually to ensure the x-axis has the correct width and location.
Did you try setting theIs is possible to fix the width of the x-axis?Width
,Height
,AutoAdjustPlotMargins
andPlotMargins
of thePlot
control? If you do this, I think the size of the plot should be fixed.
It is easy to add Rendering/Rendered events to thePlotModel
, but I would like to avoid it if it is not really needed.
ThePlotModel
was meant to be the abstraction of the plot view - so it contains both the "plot area" and all the transforms that are related to the size of the view. See also https://oxyplot.codeplex.com/workitem/10133 which is related to this.
For example a plot will display a line series with data that can vary fro 0 to 1000000.
Let's assume we fix the plot width. If the data is within the range 0-10 then the x-axis width will have a certain value. However if we load data in the range between 10000 -100000 then the x-axis width will shrink to accommodate the extra digits displayed on the Y-axis.
It gets even worse if we enable the Y-axis title. (the x-axis shrinks even more.)
In other words rather than fixing the plot width, we need a way of fixing the x-axis width and allow the plot width to move dynamically. Ideally it would be great to anchor the origin of the x-axis as well.
If this is not possible, then having a "rendered" event would allow us to do all the calculations manually to ensure the x-axis has the correct width and location.
Customer support service by UserEcho