WPF+PRISM 如何使弹出 window owner as main window
WPF+PRISM How to make the popup window owner as main window
我无法将 Popup window 的所有者设置为 Application Main window。
这是我做的。
创建了带有自定义弹出窗口的 Main Window。Window。
<Window x:Class="MainWindow"
...
<Window.Resources>
<Style x:Key="MessageWindowStyle" TargetType="{x:Type Window}">
<Setter Property="Background" Value="Transparent" />
<Setter Property="WindowStyle" Value="None" />
<Setter Property="ResizeMode" Value="NoResize" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="ShowInTaskbar" Value="False"/>
<Setter Property="AllowsTransparency" Value="True"/>
</Style>
</Window.Resources>
<i:Interaction.Triggers>
<interactionRequest:InteractionRequestTrigger SourceObject="{Binding MessageRequest, Mode=OneWay}">
<interactionRequest:PopupWindowAction IsModal="True" CenterOverAssociatedObject="True" WindowStyle="{StaticResource MessageWindowStyle}" >
<interactionRequest:PopupWindowAction.WindowContent>
<controls:PageCustomPopup />
</interactionRequest:PopupWindowAction.WindowContent>
</interactionRequest:PopupWindowAction>
</interactionRequest:InteractionRequestTrigger>
</i:Interaction.Triggers>
...
</Window>
PageCustomPopup.xaml
这是弹出窗口 window 的基本 xaml。
<UserControl x:Class="PageCustomPopup"
...
</UserControl>
- PageCustomPopup.xaml.cs
在此页面代码隐藏中,我尝试在加载弹出 window 时设置父级。但它抛出异常。
public partial class PageCustomPopup : UserControl, InteractionRequestAware, INotifyPropertyChanged
{
public PageCustomPopup()
{
Loaded += (sender, args) =>
{
try
{
var parentWindow = this.Parent as Window;
if (parentWindow != null)
{
// This line fails with "Cannot set the Owner after the window is displayed."
//parentWindow.Owner = Application.Current.MainWindow;
// First, default to the main window's dimensions
parentWindow.Width = Application.Current.MainWindow.Width;
parentWindow.Height = Application.Current.MainWindow.Height;
parentWindow.Left = Application.Current.MainWindow.Left;
parentWindow.Top = Application.Current.MainWindow.Top;
}
}
}
}
}
MainWindow 后面的代码。
public InteractionRequest<Notification> MessageRequest { get; private set; }
public MainWindow()
{
...
MessageRequest = new InteractionRequest<Notification>();
...
}
void Button_OnClick(object sender, EventArgs e)
{
MessageRequest.Raise(new Notification(){ Title = "Title Text", Content = "Message to Display"});
}
显示自定义弹出窗口 window 时,它会正确显示在主 window 的中心。
但问题是,当所有的windows都最小化后,如果点击任务栏上的应用程序图标,会显示应用程序主window,并且无法正常工作。不能select任何东西。
弹出窗口 window 已隐藏,无法显示在前面。
将 Popup window 放在前面的唯一方法是使用 "Alt+Tab" 键。
我的问题是,如何将自定义弹出窗口 window 所有者设置为 Application.Current.MainWindow?
因此,通过 selecting 任务栏图标或 Alt+Tab,显示 Mainwindow 和弹出窗口 window。
如错误所述,您将 属性 设置得太晚了。您在 Loaded 事件中设置它,因此 window 已经加载。您需要在显示 window 之前设置它。正如您所知,这已在 Prism for WPF 的最新预览版中得到修复。
如果您想升级 NuGets 以使用最新的预览版。以下是修复列表:
https://github.com/PrismLibrary/Prism/wiki/Release-Notes--Jan-10,-2016#prism-for-wpf-611-pre2
与此同时,如果您不想使用预览版,您可以自己实现,派生自 PopupWindowAction
:
public class PopupChildWindowAction : PopupWindowAction
{
public static readonly DependencyProperty WindowOwnerProperty = DependencyProperty.Register(
"WindowOwner", typeof (Window), typeof (PopupChildWindowAction), new PropertyMetadata(default(Window)));
public Window WindowOwner
{
get { return (Window) GetValue(WindowOwnerProperty); }
set { SetValue(WindowOwnerProperty, value); }
}
protected override Window GetWindow(INotification notification)
{
Window wrapperWindow;
if (this.WindowContent != null)
{
wrapperWindow = this.CreateWindow();
if (wrapperWindow == null)
throw new NullReferenceException("CreateWindow cannot return null");
wrapperWindow.Owner = WindowOwner;
wrapperWindow.DataContext = (object)notification;
wrapperWindow.Title = notification.Title;
this.PrepareContentForWindow(notification, wrapperWindow);
}
else
wrapperWindow = this.CreateDefaultWindow(notification);
if (this.WindowStyle != null)
wrapperWindow.Style = this.WindowStyle;
return wrapperWindow;
}
}
用法:
<i:Interaction.Triggers>
<interactionRequest:InteractionRequestTrigger SourceObject="{Binding MessageRequest, Mode=OneWay}">
<local:PopupChildWindowAction IsModal="True" CenterOverAssociatedObject="True" WindowStyle="{StaticResource MessageWindowStyle}"
WindowOwner="{Binding ElementName=MyMainWindow}">
<interactionRequest:PopupWindowAction.WindowContent>
<local:PageCustomPopup />
</interactionRequest:PopupWindowAction.WindowContent>
</local:PopupChildWindowAction>
</interactionRequest:InteractionRequestTrigger>
</i:Interaction.Triggers>
刚刚更新@Szabolcs 的回答。实际上,我发现有些功能在我的 PRISM 版本中不可用。此外,微不足道的是我的对话框的样式没有保留,所以这段代码解决了我的问题。
protected override Window GetWindow(INotification notification)
{
Window wrapperWindow;
if (this.WindowContent != null)
{
wrapperWindow = new Window();
if (wrapperWindow == null)
throw new NullReferenceException("CreateWindow cannot return null");
wrapperWindow.Owner = WindowOwner;
wrapperWindow.DataContext = (object)notification;
wrapperWindow.Title = notification.Title;
this.PrepareContentForWindow(notification, wrapperWindow);
}
else
wrapperWindow = this.CreateDefaultWindow(notification);
return wrapperWindow;
}
以下一组行未编译,因为(可能是由于不同版本的 PRISM 组件)。所以我用 wrapperWindow = new Window() 初始化并在行为 class 的 Loaded 事件上应用样式如下。
AssociatedObject.Loaded += (sender, e) =>
{
// get the window
Window window = Window.GetWindow((UserControl)sender);
if (window != null)
{
window.WindowStyle = WindowStyle.None;
window.ResizeMode = ResizeMode.NoResize;
window.Background = Brushes.Transparent;
window.WindowStartupLocation = WindowStartupLocation.CenterOwner;
}
};
我不得不更改 xaml 部分,因为我的主要 windnow 元素名称不可用
<presentBehaviors:PopupChildWindowAction IsModal="False" CenterOverAssociatedObject="True" WindowOwner="{Binding RelativeSource={RelativeSource AncestorType=Window}}">
我无法将 Popup window 的所有者设置为 Application Main window。
这是我做的。
创建了带有自定义弹出窗口的 Main Window。Window。
<Window x:Class="MainWindow" ... <Window.Resources> <Style x:Key="MessageWindowStyle" TargetType="{x:Type Window}"> <Setter Property="Background" Value="Transparent" /> <Setter Property="WindowStyle" Value="None" /> <Setter Property="ResizeMode" Value="NoResize" /> <Setter Property="BorderThickness" Value="1" /> <Setter Property="SnapsToDevicePixels" Value="True" /> <Setter Property="ShowInTaskbar" Value="False"/> <Setter Property="AllowsTransparency" Value="True"/> </Style> </Window.Resources> <i:Interaction.Triggers> <interactionRequest:InteractionRequestTrigger SourceObject="{Binding MessageRequest, Mode=OneWay}"> <interactionRequest:PopupWindowAction IsModal="True" CenterOverAssociatedObject="True" WindowStyle="{StaticResource MessageWindowStyle}" > <interactionRequest:PopupWindowAction.WindowContent> <controls:PageCustomPopup /> </interactionRequest:PopupWindowAction.WindowContent> </interactionRequest:PopupWindowAction> </interactionRequest:InteractionRequestTrigger> </i:Interaction.Triggers> ... </Window>
PageCustomPopup.xaml
这是弹出窗口 window 的基本 xaml。
<UserControl x:Class="PageCustomPopup"
...
</UserControl>
- PageCustomPopup.xaml.cs
在此页面代码隐藏中,我尝试在加载弹出 window 时设置父级。但它抛出异常。
public partial class PageCustomPopup : UserControl, InteractionRequestAware, INotifyPropertyChanged
{
public PageCustomPopup()
{
Loaded += (sender, args) =>
{
try
{
var parentWindow = this.Parent as Window;
if (parentWindow != null)
{
// This line fails with "Cannot set the Owner after the window is displayed."
//parentWindow.Owner = Application.Current.MainWindow;
// First, default to the main window's dimensions
parentWindow.Width = Application.Current.MainWindow.Width;
parentWindow.Height = Application.Current.MainWindow.Height;
parentWindow.Left = Application.Current.MainWindow.Left;
parentWindow.Top = Application.Current.MainWindow.Top;
}
}
}
}
}
MainWindow 后面的代码。
public InteractionRequest<Notification> MessageRequest { get; private set; } public MainWindow() { ... MessageRequest = new InteractionRequest<Notification>(); ... } void Button_OnClick(object sender, EventArgs e) { MessageRequest.Raise(new Notification(){ Title = "Title Text", Content = "Message to Display"}); }
显示自定义弹出窗口 window 时,它会正确显示在主 window 的中心。
但问题是,当所有的windows都最小化后,如果点击任务栏上的应用程序图标,会显示应用程序主window,并且无法正常工作。不能select任何东西。
弹出窗口 window 已隐藏,无法显示在前面。
将 Popup window 放在前面的唯一方法是使用 "Alt+Tab" 键。
我的问题是,如何将自定义弹出窗口 window 所有者设置为 Application.Current.MainWindow? 因此,通过 selecting 任务栏图标或 Alt+Tab,显示 Mainwindow 和弹出窗口 window。
如错误所述,您将 属性 设置得太晚了。您在 Loaded 事件中设置它,因此 window 已经加载。您需要在显示 window 之前设置它。正如您所知,这已在 Prism for WPF 的最新预览版中得到修复。
如果您想升级 NuGets 以使用最新的预览版。以下是修复列表:
https://github.com/PrismLibrary/Prism/wiki/Release-Notes--Jan-10,-2016#prism-for-wpf-611-pre2
与此同时,如果您不想使用预览版,您可以自己实现,派生自 PopupWindowAction
:
public class PopupChildWindowAction : PopupWindowAction
{
public static readonly DependencyProperty WindowOwnerProperty = DependencyProperty.Register(
"WindowOwner", typeof (Window), typeof (PopupChildWindowAction), new PropertyMetadata(default(Window)));
public Window WindowOwner
{
get { return (Window) GetValue(WindowOwnerProperty); }
set { SetValue(WindowOwnerProperty, value); }
}
protected override Window GetWindow(INotification notification)
{
Window wrapperWindow;
if (this.WindowContent != null)
{
wrapperWindow = this.CreateWindow();
if (wrapperWindow == null)
throw new NullReferenceException("CreateWindow cannot return null");
wrapperWindow.Owner = WindowOwner;
wrapperWindow.DataContext = (object)notification;
wrapperWindow.Title = notification.Title;
this.PrepareContentForWindow(notification, wrapperWindow);
}
else
wrapperWindow = this.CreateDefaultWindow(notification);
if (this.WindowStyle != null)
wrapperWindow.Style = this.WindowStyle;
return wrapperWindow;
}
}
用法:
<i:Interaction.Triggers>
<interactionRequest:InteractionRequestTrigger SourceObject="{Binding MessageRequest, Mode=OneWay}">
<local:PopupChildWindowAction IsModal="True" CenterOverAssociatedObject="True" WindowStyle="{StaticResource MessageWindowStyle}"
WindowOwner="{Binding ElementName=MyMainWindow}">
<interactionRequest:PopupWindowAction.WindowContent>
<local:PageCustomPopup />
</interactionRequest:PopupWindowAction.WindowContent>
</local:PopupChildWindowAction>
</interactionRequest:InteractionRequestTrigger>
</i:Interaction.Triggers>
刚刚更新@Szabolcs 的回答。实际上,我发现有些功能在我的 PRISM 版本中不可用。此外,微不足道的是我的对话框的样式没有保留,所以这段代码解决了我的问题。
protected override Window GetWindow(INotification notification)
{
Window wrapperWindow;
if (this.WindowContent != null)
{
wrapperWindow = new Window();
if (wrapperWindow == null)
throw new NullReferenceException("CreateWindow cannot return null");
wrapperWindow.Owner = WindowOwner;
wrapperWindow.DataContext = (object)notification;
wrapperWindow.Title = notification.Title;
this.PrepareContentForWindow(notification, wrapperWindow);
}
else
wrapperWindow = this.CreateDefaultWindow(notification);
return wrapperWindow;
}
以下一组行未编译,因为(可能是由于不同版本的 PRISM 组件)。所以我用 wrapperWindow = new Window() 初始化并在行为 class 的 Loaded 事件上应用样式如下。
AssociatedObject.Loaded += (sender, e) =>
{
// get the window
Window window = Window.GetWindow((UserControl)sender);
if (window != null)
{
window.WindowStyle = WindowStyle.None;
window.ResizeMode = ResizeMode.NoResize;
window.Background = Brushes.Transparent;
window.WindowStartupLocation = WindowStartupLocation.CenterOwner;
}
};
我不得不更改 xaml 部分,因为我的主要 windnow 元素名称不可用
<presentBehaviors:PopupChildWindowAction IsModal="False" CenterOverAssociatedObject="True" WindowOwner="{Binding RelativeSource={RelativeSource AncestorType=Window}}">