问题
Is it possible to compare the relative Z order (which one will draw on top) of two WPF controls regardless of their relation in the logical/visual tree structure and what layout containers are used?
I need this to be able to determine the visible regions of a control that might be overlapped by others. My plan is to start with the control geometry and intersect with the geometries of all the controls that will draw on top using CombinedGeometry having the GeometryCombineMode property set to "Exclude".
Update:
If everyone is interested I've used gdi32 API to calculate the visible area.
[DllImport("gdi32.dll")]
static extern IntPtr CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect);
[DllImport("gdi32.dll")]
static extern int CombineRgn(IntPtr hrgnDest, IntPtr hrgnSrc1, IntPtr hrgnSrc2, int fnCombineMode);
[DllImport("gdi32.dll")]
static extern int GetRegionData(IntPtr hRgn, uint dwCount, IntPtr lpRgnData);
[DllImport("gdi32.dll")]
static extern bool SetRectRgn(IntPtr hRgn, int nLeftRect, int nTopRect, int nRightRect, int nBottomRect);
[DllImport("gdi32.dll")]
static extern bool DeleteObject(IntPtr hObject);
回答1:
I ran into a similar problem last night. The goal for me was to determine whether one control would be drawn in front of another. I searched for about 45 minutes and couldn't find a solution provided by APIs so I had to traverse the visual tree to find out which one would be drawn on top. So, I guess based on my research my answer is no, you can't compare relative z order without looking at the visual tree yourself.
In case you still need, here is the code I used to find the relative z order of controls (InFrontOf method), which also takes into account manually setting the .ZOrder property of controls (works for my code but not thoroughly tested, does not work if ZOrder property of control is set to negative value).
private bool InFrontOf(FrameworkElement c1, FrameworkElement c2){
Panel root = FindWindowRoot(c1); // Find the root of the document, assumes that c1 and c2 are part of the same document
Trace.Assert(root != null, "root of ui element is not a window or a panel that contains children");
int z1 = Math.Max(Panel.GetZIndex(c1), GetDrawOrder(root, c1));
int z2 = Math.Max(Panel.GetZIndex(c2), GetDrawOrder(root, c2));
return z1 > z2;
}
private Panel FindWindowRoot(FrameworkElement child)
{
FrameworkElement current = child;
while(current as Window == null)
{
current = (FrameworkElement)VisualTreeHelper.GetParent(current);
}
return ((Window)current).Content as Panel;
}
private int GetDrawOrder(Panel root, FrameworkElement needle)
{
int result = 0;
FrameworkElement current = root;
Queue<FrameworkElement> toSearch = new Queue<FrameworkElement>();
toSearch.Enqueue(current);
while(needle != current)
{
if(current is Panel)
{
Panel p = (Panel) current;
foreach (FrameworkElement frameworkElement in p.Children)
{
toSearch.Enqueue(frameworkElement);
}
}
if (current is ContentControl)
{
ContentControl cc = (ContentControl)current;
if(cc.Content as FrameworkElement != null)
toSearch.Enqueue(cc.Content as FrameworkElement);
}
current = toSearch.Dequeue();
result++;
}
return result;
}
来源:https://stackoverflow.com/questions/8186844/how-to-compare-the-relative-z-order-of-two-wpf-controls-that-are-part-of-the-sam