BringToFront в WPF
Мне нужно запустить пользовательский элемент управления в WPF.
псевдокод
OnMouseDown()
{
if (this.parent != null)
this.parent.BringToFront(this);
}
Я знаю, что я знаю, что есть ZIndex, но до сих пор не понимаю, как заменить простой WinForm BringToFront
на parent.SetZIndex(this, ?MaxZIndex(parent)? + 1)
?
Возможно, есть лучший способ сделать это в такой классной вещи, как WPF?!..
Ответы
Ответ 1
Вот функция расширения, которая добавляет метод BringToFront ко всем элементам FrameworkElements, которые содержатся в панели.
public static class FrameworkElementExt
{
public static void BringToFront(this FrameworkElement element)
{
if (element == null) return;
Panel parent = element.Parent as Panel;
if (parent == null) return;
var maxZ = parent.Children.OfType<UIElement>()
.Where(x => x != element)
.Select(x => Panel.GetZIndex(x))
.Max();
Panel.SetZIndex(element, maxZ + 1);
}
}
Ответ 2
На самом деле лучшим, на что вы можете надеяться, является создание элемента самого верхнего по отношению к любым элементам-братьями в одной и той же родительской панели (например, StackPanel, Grid, Canvas и т.д.). Z-порядок элементов в панелях контролируется приложением Panel.ZIndex.
Например:
<Grid>
<Rectangle Fill="Blue" Width="50" Height="50" Panel.ZIndex="1" />
<Rectangle Fill="Red" Width="50" Height="50" Panel.ZIndex="0" />
</Grid>
В этом примере синий прямоугольник появится сверху. Это объясняется немного больше в этом сообщении .
Также существует проблема с изменениями Panel.ZIndex, которые не сразу отражаются в пользовательском интерфейсе. Существует частный метод, который позволяет обновлять z-index, но поскольку он закрыт, не рекомендуется использовать его. Чтобы обойти это, вам придется удалить и повторно добавить детей.
Однако вы не можете сделать любой данный элемент самым большим. Например:
<Grid>
<Grid>
<Rectangle Fill="Blue" Width="50" Height="50" Panel.ZIndex="1" />
<Rectangle Fill="Red" Width="50" Height="50" Panel.ZIndex="0" />
</Grid>
<Grid>
<Rectangle Fill="Green" Width="50" Height="50" Panel.ZIndex="0" />
<Rectangle Fill="Yellow" Width="50" Height="50" Panel.ZIndex="0" />
</Grid>
</Grid>
В этом случае отобразится желтый прямоугольник. Потому что вторая внутренняя сетка показана поверх первой внутренней сетки и все содержимое. Вам нужно будет изменить его так, чтобы вывести синий прямоугольник вверху:
<Grid>
<Grid Panel.ZIndex="1">
<Rectangle Fill="Blue" Width="50" Height="50" Panel.ZIndex="1" />
<Rectangle Fill="Red" Width="50" Height="50" Panel.ZIndex="0" />
</Grid>
<Grid Panel.ZIndex="0">
<Rectangle Fill="Green" Width="50" Height="50" Panel.ZIndex="0" />
<Rectangle Fill="Yellow" Width="50" Height="50" Panel.ZIndex="0" />
</Grid>
</Grid>
При работе с ItemsControl актуальным является этот вопрос. У большинства других элементов управления есть один ребенок, но вам все равно нужно вывести их вперед, чтобы сделать его одним из самых лучших.
Наконец, Adorners - хороший способ поставить вещи поверх всего, но они не являются частью основного визуального дерева. Поэтому я не уверен, что это сработает в вашем случае.
Ответ 3
Я попробовал canvas.zindex, и это не сработало, но решение, которое для меня использовало, использует Border в элементе управления Popup:
<Popup IsOpen="True/False">
<Border Background="White">
<DatePicker/>
</Border>
</Popup>
Ответ 4
Я нашел лучшее решение. Получите это:
foreach (var item in Grid1.Children)
{
if ((item as UIElement).Uid == "StackPan1")
{
UIElement tmp = item as UIElement;
Grid1.Children.Remove(item as UIElement);
Grid1.Children.Add(tmp);
break;
}
}
Это просто пример, а не универсальный метод. Но вы можете использовать его в приложениях с динамическим добавлением элементов управления. Этот код просто добавляет элемент, который вы хотите нанести на вершину, и на UIElementCollection. Он работает, если все ваши элементы имеют одинаковый ZIndex.