-
Notifications
You must be signed in to change notification settings - Fork 980
Description
Doing my best to format it, as I'm not a git expert by any means.
Steps to reproduce
- Put a plotview inside a WPF Popup
- Display the popup
- See a white graph
Platform: Windows
.NET version: 4.6.1 and others
Expected behaviour
The graph should appear normally inside a popup
Actual behaviour
The graph appears Empty
Why does it happen ?
In PlotViewBase , you're checking if the graph is part of the visual tree by checking if the ancestor is a window :
/// <summary>
/// Gets a value indicating whether the <see cref="PlotViewBase"/> is connected to the visual tree.
/// </summary>
/// <returns><c>true</c> if the PlotViewBase is connected to the visual tree; <c>false</c> otherwise.</returns>
private bool IsInVisualTree()
{
DependencyObject dpObject = this;
while ((dpObject = VisualTreeHelper.GetParent(dpObject)) != null)
{
if (dpObject is Window)
{
return true;
}
}
return false;
}
In the case of a WPF popup, the ancestor is a Popuproot :

The fix
We need to check if the ancestor is also a Popuproot. If so, it's in the visual tree. But as the popuproot is an internal type, you can't check against it easily. The best way I found is to check if the logical parent of the PopupRoot is a Popup :
/// <summary>
/// Gets a value indicating whether the <see cref="PlotViewBase"/> is connected to the visual tree.
/// </summary>
/// <returns><c>true</c> if the PlotViewBase is connected to the visual tree; <c>false</c> otherwise.</returns>
private bool IsInVisualTree()
{
DependencyObject dpObject = this;
while ((dpObject = VisualTreeHelper.GetParent(dpObject)) != null)
{
if (dpObject is Window)
{
return true;
}
//Check if the logical parent is a popup. If so, we found the popuproot
var logicalRoot = LogicalTreeHelper.GetParent(dpObject);
if (logicalRoot is Popup)
{
// popup root found here
return true;
}
}
return false;
}
This isn't enough, as in PlotView, you're getting the window parent from the Visual tree using this call :
/// <summary>
/// Returns a reference to the window object that hosts the dependency object in the visual tree.
/// </summary>
/// <returns> The host window from the visual tree.</returns>
private Window GetAncestorWindowFromVisualTree(DependencyObject startElement)
{
DependencyObject parent = startElement;
while (!(parent is Window))
{
if (parent == null) { break; }
parent = VisualTreeHelper.GetParent(parent);
}
return parent as Window ?? Window.GetWindow(this);
}
I find this Window check superfluous, as if you're there, you have already checked you're in the visual tree. You can thus just walk the visual tree and get the root here, no check needed, and you only need a Visual type in the call, not a Window type :
private Visual GetAncestorVisualFromVisualTree(DependencyObject startElement)
{
DependencyObject child = startElement;
DependencyObject parent = VisualTreeHelper.GetParent(child);
while (parent != null)
{
child = parent;
parent = VisualTreeHelper.GetParent(child);
}
return child is Visual visualChild ? visualChild : Window.GetWindow(this);
}
This makes Oxyplot work flawlessly in a popup.
Feel free to correct me and point any mistakes !
Following writing all this, I'll try to a PR - not sure I'll succeed though :D