C# 设计一个;“忙”;使用InteractionRequests的对话框
我目前正在使用Prism的C# 设计一个;“忙”;使用InteractionRequests的对话框,c#,mvvm,prism,prism-4,interaction,C#,Mvvm,Prism,Prism 4,Interaction,我目前正在使用Prism的交互请求来显示新窗口。我使用它们进行简单的确认,以及显示带有自定义视图/视图模型的窗口,如下所示。无论如何,在所有这些情况下,我显示窗口,窗口上的某个按钮负责关闭它。我想显示一个窗口,让调用它的对象负责关闭它 以下是我的实现: 行动通知 public abstract class ActionNotification: Notification, INotifyPropertyChanged, IPopupWindowActionAware { public e
交互请求
来显示新窗口。我使用它们进行简单的确认,以及显示带有自定义视图/视图模型的窗口,如下所示。无论如何,在所有这些情况下,我显示窗口,窗口上的某个按钮负责关闭它。我想显示一个窗口,让调用它的对象负责关闭它
以下是我的实现:
行动通知
public abstract class ActionNotification: Notification, INotifyPropertyChanged, IPopupWindowActionAware
{
public event PropertyChangedEventHandler PropertyChanged;
// IPopupWindowActionAware
public System.Windows.Window HostWindow { get; set; } // Set when the "action" in the view is triggered
public Notification HostNotification { get; set; } // Set when the "action" in the view is triggered
public ActionNotification(string content)
{
this.Content = content;
}
public void CompleteAction()
{
if (this.HostWindow != null)
{
this.HostWindow.Close();
}
}
// INotifyPropertyChange implementation
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
调用方法
/// <summary>
/// Pushes a unit of work onto a separate thread and notifies the view to display an action notification
/// </summary>
/// <param name="actionNotification">The notification object for the view to display</param>
/// <param name="act">The unit of work to perform on a separate thread</param>
private void DoWorkAndRaiseAction(ActionNotification actionNotification, Action act)
{
Task.Factory.StartNew(() =>
{
try
{
act();
}
finally
{
Application.Current.Dispatcher.Invoke((Action)(() => actionNotification.CompleteAction()));
}
});
ActionInteractionReq.Raise(actionNotification);
}
调用Raise
时,将触发PopupUpIndowAction并创建一个新窗口。然后它会在该窗口上显示对话框
EDIT3:根据评论中的建议,我已经包括了弹出窗口操作
。为了简洁起见,我删掉了一些不相关的代码
public class PopupWindowAction : TriggerAction<FrameworkElement>
{
/*
Here is where a few dependency properties live that dictate things like Window size and other stuff, e.g.
/// <summary>
/// Determines if the content should be shown in a modal window or not.
/// </summary>
public static readonly DependencyProperty IsModalProperty =
DependencyProperty.Register(
"IsModal",
typeof(bool),
typeof(PopupWindowAction),
new PropertyMetadata(null));
*/
/*
Here is where the accessors live for the DPs, e.g.
/// <summary>
/// Gets or sets if the window will be modal or not.
/// </summary>
public bool IsModal
{
get { return (bool)GetValue(IsModalProperty); }
set { SetValue(IsModalProperty, value); }
}
*/
#region PopupWindowAction logic
/// <summary>
/// Displays the child window and collects results for <see cref="IInteractionRequest"/>.
/// </summary>
/// <param name="parameter">The parameter to the action. If the action does not require a parameter, the parameter may be set to a null reference.</param>
protected override void Invoke(object parameter)
{
var args = parameter as InteractionRequestedEventArgs;
if (args == null)
{
return;
}
// If the WindowContent shouldn't be part of another visual tree.
if (this.WindowContent != null && this.WindowContent.Parent != null)
{
return;
}
var wrapperWindow = this.GetWindow(args.Context); // args.Context here is the Notification object I'm passing to the InteractionRequest
var callback = args.Callback;
EventHandler handler = null;
handler =
(o, e) =>
{
wrapperWindow.Closed -= handler;
wrapperWindow.Owner = null;
wrapperWindow.Content = null;
callback();
};
wrapperWindow.Closed += handler;
if (this.IsModal)
{
wrapperWindow.ShowDialog();
}
else
{
wrapperWindow.Show();
}
}
/// <summary>
/// Checks if the WindowContent or its DataContext implements IPopupWindowActionAware and IRegionManagerAware.
/// If so, it sets the corresponding values.
/// Also, if WindowContent does not have a RegionManager attached, it creates a new scoped RegionManager for it.
/// </summary>
/// <param name="notification">The notification to be set as a DataContext in the HostWindow.</param>
/// <param name="wrapperWindow">The HostWindow</param>
protected void PrepareContentForWindow(Notification notification, Window wrapperWindow)
{
if (this.WindowContent == null)
{
return;
}
// We set the WindowContent as the content of the window.
wrapperWindow.Content = this.WindowContent;
/* Code removed for brevity */
// If the WindowContent implements IPopupWindowActionAware, we set the corresponding values.
IPopupWindowActionAware popupAwareContent = this.WindowContent as IPopupWindowActionAware;
if (popupAwareContent != null)
{
popupAwareContent.HostWindow = wrapperWindow;
popupAwareContent.HostNotification = notification;
}
// If the WindowContent's DataContext implements IPopupWindowActionAware, we set the corresponding values.
IPopupWindowActionAware popupAwareDataContext = this.WindowContent.DataContext as IPopupWindowActionAware;
if (popupAwareDataContext != null)
{
popupAwareDataContext.HostWindow = wrapperWindow;
popupAwareDataContext.HostNotification = notification;
}
}
#endregion
#region Window creation methods
/// <summary>
/// Returns the window to display as part of the trigger action.
/// </summary>
/// <param name="notification">The notification to be set as a DataContext in the window.</param>
/// <returns></returns>
protected Window GetWindow(Notification notification)
{
Window wrapperWindow;
if (this.WindowContent != null)
{
wrapperWindow = new Window();
wrapperWindow.WindowStyle = this.WindowStyle;
// If the WindowContent does not have its own DataContext, it will inherit this one.
wrapperWindow.DataContext = notification;
wrapperWindow.Title = notification.Title ?? string.Empty;
this.PrepareContentForWindow(notification, wrapperWindow);
}
else
{
wrapperWindow = this.CreateDefaultWindow(notification);
wrapperWindow.DataContext = notification;
}
return wrapperWindow;
}
private Window CreateDefaultWindow(Notification notification)
{
return new DefaultNotificationWindow
{
NotificationTemplate = this.ContentTemplate,
MessageBoxImage = GetImageFromNotification(notification as ZBaseNotification)
};
}
#endregion
}
公共类PopupWindowAction:TriggerAction
{
/*
这里有一些依赖属性,它们规定了窗口大小和其他内容,例如。
///
///确定内容是否应显示在模式窗口中。
///
公共静态只读从属属性IsModalProperty=
从属属性。寄存器(
“IsModal”,
类型(bool),
类型(PopupUpIndowAction),
新属性元数据(空);
*/
/*
这里是DPs的访问器所在的位置,例如。
///
///获取或设置窗口是否为模态窗口。
///
公共图书馆
{
获取{return(bool)GetValue(IsModalProperty);}
set{SetValue(IsModalProperty,value);}
}
*/
#区域操作逻辑
///
///显示子窗口并收集子窗口的结果。
///
///操作的参数。如果操作不需要参数,则可将参数设置为空引用。
受保护的覆盖无效调用(对象参数)
{
var args=作为InteractionRequestedEventArgs的参数;
如果(args==null)
{
返回;
}
//如果WindowContent不应该是另一个可视树的一部分。
if(this.WindowContent!=null&&this.WindowContent.Parent!=null)
{
返回;
}
var wrapperWindow=this.GetWindow(args.Context);//args.Context这里是我传递给InteractionRequest的通知对象
var callback=args.callback;
EventHandler=null;
处理者=
(o,e)=>
{
wrapperWindow.Closed-=处理程序;
wrapperWindow.Owner=null;
wrapperWindow.Content=null;
回调();
};
wrapperWindow.Closed+=处理程序;
if(this.IsModal)
{
wrapperWindow.ShowDialog();
}
其他的
{
wrapperWindow.Show();
}
}
///
///检查WindowContent或其DataContext是否实现IPoppupWindowActionAware和iRegionManager。
///如果是,则设置相应的值。
///此外,如果WindowContent没有连接RegionManager,它会为其创建一个新的作用域RegionManager。
///
///要在HostWindow中设置为DataContext的通知。
///窗口
受保护的void PrepareContentForWindow(通知、窗口包装器窗口)
{
if(this.WindowContent==null)
{
返回;
}
//我们将WindowContent设置为窗口的内容。
wrapperWindow.Content=this.WindowContent;
/*为简洁起见,删除了代码*/
//如果WindowContent实现IPoppupWindowActionAware,则设置相应的值。
IPoppupWindowActionAware popupAwareContent=此.WindowContent为IPoppupWindowActionAware;
if(popupAwareContent!=null)
{
popupAwareContent.HostWindow=包装器窗口;
popupAwareContent.HostNotification=通知;
}
//如果WindowContent的DataContext实现了IPopupWindowActionAware,我们将设置相应的值。
IPoppupWindowActionAware popupAwareDataContext=this.WindowContent.DataContext作为IPoppupWindowActionAware;
if(popupAwareDataContext!=null)
{
popupAwareDataContext.HostWindow=包装器窗口;
popupAwareDataContext.HostNotification=通知;
}
}
#端区
#区域窗口创建方法
///
///返回要作为触发器操作的一部分显示的窗口。
///
///要在窗口中设置为DataContext的通知。
///
受保护的窗口GetWindow(通知)
{
窗口包装器窗口;
如果(this.WindowContent!=null)
{
wrapperWindow=新窗口();
wrapperWindow.WindowsStyle=此.WindowsStyle;
//如果WindowContent没有自己的DataContext,它将继承此DataContext。
wrapperWindow.DataContext=通知;
wrapperWindow.Title=notification.Title??string.Empty;
此.PrepareContentForWindow(通知,包装窗口);
}
其他的
{
wrapperWindow=this.CreateDefaultWindow(通知);
wrapperWindow.DataContext=通知;
}
返回包装器窗口;
}
私有窗口CreateDefaultWindow(通知)
{
返回新的DefaultNotificationWindow
{
NotificationTemplate=this.ContentTemplate,
MessageBoxImage=GetImageFromNotification(通知为ZBaseNotification)
};
}
#端区
}
这里的根本问题是启动异步操作的代码和
public class PopupWindowAction : TriggerAction<FrameworkElement>
{
/*
Here is where a few dependency properties live that dictate things like Window size and other stuff, e.g.
/// <summary>
/// Determines if the content should be shown in a modal window or not.
/// </summary>
public static readonly DependencyProperty IsModalProperty =
DependencyProperty.Register(
"IsModal",
typeof(bool),
typeof(PopupWindowAction),
new PropertyMetadata(null));
*/
/*
Here is where the accessors live for the DPs, e.g.
/// <summary>
/// Gets or sets if the window will be modal or not.
/// </summary>
public bool IsModal
{
get { return (bool)GetValue(IsModalProperty); }
set { SetValue(IsModalProperty, value); }
}
*/
#region PopupWindowAction logic
/// <summary>
/// Displays the child window and collects results for <see cref="IInteractionRequest"/>.
/// </summary>
/// <param name="parameter">The parameter to the action. If the action does not require a parameter, the parameter may be set to a null reference.</param>
protected override void Invoke(object parameter)
{
var args = parameter as InteractionRequestedEventArgs;
if (args == null)
{
return;
}
// If the WindowContent shouldn't be part of another visual tree.
if (this.WindowContent != null && this.WindowContent.Parent != null)
{
return;
}
var wrapperWindow = this.GetWindow(args.Context); // args.Context here is the Notification object I'm passing to the InteractionRequest
var callback = args.Callback;
EventHandler handler = null;
handler =
(o, e) =>
{
wrapperWindow.Closed -= handler;
wrapperWindow.Owner = null;
wrapperWindow.Content = null;
callback();
};
wrapperWindow.Closed += handler;
if (this.IsModal)
{
wrapperWindow.ShowDialog();
}
else
{
wrapperWindow.Show();
}
}
/// <summary>
/// Checks if the WindowContent or its DataContext implements IPopupWindowActionAware and IRegionManagerAware.
/// If so, it sets the corresponding values.
/// Also, if WindowContent does not have a RegionManager attached, it creates a new scoped RegionManager for it.
/// </summary>
/// <param name="notification">The notification to be set as a DataContext in the HostWindow.</param>
/// <param name="wrapperWindow">The HostWindow</param>
protected void PrepareContentForWindow(Notification notification, Window wrapperWindow)
{
if (this.WindowContent == null)
{
return;
}
// We set the WindowContent as the content of the window.
wrapperWindow.Content = this.WindowContent;
/* Code removed for brevity */
// If the WindowContent implements IPopupWindowActionAware, we set the corresponding values.
IPopupWindowActionAware popupAwareContent = this.WindowContent as IPopupWindowActionAware;
if (popupAwareContent != null)
{
popupAwareContent.HostWindow = wrapperWindow;
popupAwareContent.HostNotification = notification;
}
// If the WindowContent's DataContext implements IPopupWindowActionAware, we set the corresponding values.
IPopupWindowActionAware popupAwareDataContext = this.WindowContent.DataContext as IPopupWindowActionAware;
if (popupAwareDataContext != null)
{
popupAwareDataContext.HostWindow = wrapperWindow;
popupAwareDataContext.HostNotification = notification;
}
}
#endregion
#region Window creation methods
/// <summary>
/// Returns the window to display as part of the trigger action.
/// </summary>
/// <param name="notification">The notification to be set as a DataContext in the window.</param>
/// <returns></returns>
protected Window GetWindow(Notification notification)
{
Window wrapperWindow;
if (this.WindowContent != null)
{
wrapperWindow = new Window();
wrapperWindow.WindowStyle = this.WindowStyle;
// If the WindowContent does not have its own DataContext, it will inherit this one.
wrapperWindow.DataContext = notification;
wrapperWindow.Title = notification.Title ?? string.Empty;
this.PrepareContentForWindow(notification, wrapperWindow);
}
else
{
wrapperWindow = this.CreateDefaultWindow(notification);
wrapperWindow.DataContext = notification;
}
return wrapperWindow;
}
private Window CreateDefaultWindow(Notification notification)
{
return new DefaultNotificationWindow
{
NotificationTemplate = this.ContentTemplate,
MessageBoxImage = GetImageFromNotification(notification as ZBaseNotification)
};
}
#endregion
}
public Window HostWindow { /* call OnPropertyChanged! */ }
public void CompleteAction()
{
if (this.HostWindow != null)
{
this.HostWindow.Close();
}
else
{
this.PropertyChanged += (o, e) => {
if (e.PropertyName == "HostWindow" && this.HostWindow != null)
{
var hostWindow = this.HostWindow; // prevent closure-related bugs
// kill it whenever it appears in the future
hostWindow.Loaded += (o, e) => { hostWindow.Close(); };
// kill it right now as well if it's been shown already
// (we cannot assume anything)
if (hostWindow.IsLoaded)
{
hostWindow.Close();
}
}
};
}
}