WPF Popup ZOrder
Я использую всплывающее окно WPF, но оно появляется над каждым окном моего рабочего стола, даже когда мое приложение свернуто. Как я могу сделать так, чтобы оно оставалось только в том окне, в котором оно появилось? То же самое происходит, когда мое окно находится за другими окнами: всплывающее окно отображается над ними.
"Там должно быть что-то может быть сделано!"
Благодарю.
4 ответа
Я тоже пытался решить эту проблему и не нашел хорошего решения. Кажется, это так, как и должно работать, и вы не можете это переопределить.
Единственное решение, которое я придумала, это просто использовать обычную панель макетов и поднять ее Z-Index, так что это элемент управления верхнего уровня (этот тип имитирует всплывающее окно). Единственный раз, когда я обнаружил, что это не сработает, это когда на экране появятся WinForms через WindowsFormsHosts. Эти Winforms всегда имеют более высокий Z-индекс, чем любой другой материал WPF. Именно тогда вы должны использовать всплывающее окно, чтобы обойти это.
Поэтому я покопался в исходном коде фреймворка, чтобы увидеть, где оно на самом деле приводит к тому, что окно будет самым верхним, и это делается в закрытом вложенном классе. Тем не менее, он не предоставляет возможность быть просто дочерним всплывающим окном главного окна или самым верхним окном. Вот хак, чтобы сделать его всегда дочерним всплывающим окном. Можно легко добавить свойство зависимостей и сделать больше магии, чтобы сделать его самым лучшим.
using System;
using System.Reflection;
using System.Windows;
using System.Windows.Controls.Primitives;
namespace UI.Extensions.Wpf.Controls
{
public class ChildPopup : Popup
{
static ChildPopup()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ChildPopup), new FrameworkPropertyMetadata(typeof(ChildPopup)));
}
public ChildPopup()
{
Type baseType = this.GetType().BaseType;
dynamic popupSecHelper = GetHiddenField(this, baseType, "_secHelper");
SetHiddenField(popupSecHelper, "_isChildPopupInitialized", true);
SetHiddenField(popupSecHelper, "_isChildPopup", true);
}
protected dynamic GetHiddenField(object container, string fieldName)
{
return GetHiddenField(container, container.GetType(), fieldName);
}
protected dynamic GetHiddenField(object container, Type containerType, string fieldName)
{
dynamic retVal = null;
FieldInfo fieldInfo = containerType.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance);
if (fieldInfo != null)
{
retVal = fieldInfo.GetValue(container);
}
return retVal;
}
protected void SetHiddenField(object container, string fieldName, object value)
{
SetHiddenField(container, container.GetType(), fieldName, value);
}
protected void SetHiddenField(object container, Type containerType, string fieldName, object value)
{
FieldInfo fieldInfo = containerType.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance);
if (fieldInfo != null)
{
fieldInfo.SetValue(container, value);
}
}
}
}
Вот как я это решил:
private void Popup_Opened(object sender, EventArgs events)
{
Popup popup = (Popup)sender;
// Get window to make popop follow it when user change window's location.
Window w = Window.GetWindow(popup);
// Popups are always on top, so when another window gets focus, we
// need to close all popups.
w.Deactivated += delegate (object s, EventArgs e)
{
popup.IsOpen = false;
};
// When our dialog gets focus again, we show it back.
w.Activated += delegate (object s, EventArgs e)
{
popup.IsOpen = true;
};
}
Проверьте это: http://chriscavanagh.wordpress.com/2008/08/13/non-topmost-wpf-popup/
может быть, это может помочь вам!
Хотя я не пытался это сделать, я также читал, что это можно сделать с помощью украшателей... Мэтт Гэлбрейт предложил это на форуме MSDN, когда ему задали тот же вопрос... на тот случай, если кто-то еще читает эту ветку.