- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试实现一个系统来关闭 WPF 应用程序中的所有模态和非模态窗口(主应用程序窗口除外)。当这些窗口关闭时,任何等待对话框结果的代码都应该是被遗弃。
到目前为止,我已经考虑/尝试过两种策略:
第一个解决方案确实让应用程序关闭并且足以自动注销,但我对在等待的对话框关闭后继续执行的代码感到非常不舒服。是否有停止执行该代码的好方法?
第二个解决方案一直运行良好(调用代码被中止)但有一个严重缺陷:有时,模态和非模态窗口的某种组合快速连续关闭会导致应用程序锁定 ShowDialog
调用。 (至少,当您暂停执行时,这就是它结束的地方。)这很奇怪,因为断点清楚地表明 Closed
事件正在我打算关闭的所有窗口上引发。最终用户看到的结果是登录屏幕,无法单击但可以跳转。这么奇怪!尝试以不同的优先级调度调用均未成功,但 100 毫秒的 Task.Delay
可能已成功。 (不过,这不是真正的解决方案。)
如果每个打开的弹出窗口都在后台等待 TaskCompletionSource
,并且在 TCS 完成后尝试使用调度程序对其自身调用 Close
,为什么会一个(或多个)对话框仍然在 ShowDialog
上阻塞,即使在看到 Closed
事件被引发之后?有没有办法将这些调用正确地分派(dispatch)给 Close
以便它们成功完成?我需要特别注意窗口关闭的顺序吗?
一些伪代码-C#-混合示例:
class PopupService
{
async Task<bool> ShowModalAsync(...)
{
create TaskCompletionSource, publish event with TCS in payload
await and return the TCS result
}
void ShowModal(...)
{
// method exists for historical purposes. code calling this should
// probably be made async-aware rather than relying on the blocking
// behavior of Window.ShowDialog
create TaskCompletionSource, publish event with TCS in payload
rethrow exceptions that are set on the Task after completion but do not await
}
void CloseAllWindows(...)
{
for every known TaskCompletionSource driving a popup interaction
tcs.TrySetCanceled()
}
}
class MainWindow : Window
{
void ShowModalEventHandler(...)
{
create a new PopupWindow and set the owner, content, etc.
var window = new PopupWindow(...) { ... };
...
window.ShowDialog();
}
}
class PopupWindow : Window
{
void LoadedEventHandler(...)
{
...
Task.Run(async () =>
{
try
await the task completion source
finally
Dispatcher.Invoke(Close, DispatcherPriority.Send);
});
register closing event handlers
...
}
void ClosedEventHandler(...)
{
if(we should do something with the TCS)
try set the TCS result so the popup service caller can continue
}
}
最佳答案
使用 Window.ShowDialog
,您可以创建一个嵌套的 Dispather
消息循环。使用 await
,可以“跳转”到该内部循环并在那里继续逻辑执行 async
方法,例如:
var dialogTask = window.ShowDialogAsync();
// on the main message loop
await Task.Delay(1000);
// on the nested message loop
// ...
await dialogTask;
// expecting to be back on the main message loop
现在,如果 dialogTask
通过 TaskCompletionSource
完成,相应的 Window.ShowDialog()
调用返回到对于调用者,上述代码可能仍会在嵌套消息循环中结束,而不是在主核心消息循环中。例如,如果在对话框的 Window.Closed
事件处理程序中调用 TaskCompletionSource.SetResult/TrySetCanceled
,或者在 Window.Close()< 之前/之后调用,则可能会发生这种情况
调用。这可能会产生不希望的重入副作用,包括死锁。
通过查看您的伪代码,很难判断死锁可能在哪里。令人担忧的是,您使用 Task.Run
只是为了等待在主 UI 线程上完成的任务,或者从池线程调用主 UI 线程上的同步回调(通过 Dispatcher.Invoke
)。你当然不应该在这里需要Task.Run
。
出于类似目的,我使用以下版本的 ShowDialogAsync
。它确保由嵌套 ShowDialogAsync
调用启动的任何内部消息循环在此特定 ShowDialogAsync
任务完成之前退出:
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
namespace WpfApplication
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.Loaded += MainWindow_Loaded;
}
// testing ShowDialogAsync
async void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
var modal1 = new Window { Title = "Modal 1" };
modal1.Loaded += async delegate
{
await Task.Delay(1000);
var modal2 = new Window { Title = "Modal 2" };
try
{
await modal2.ShowDialogAsync();
}
catch (OperationCanceledException)
{
Debug.WriteLine("Cancelled: " + modal2.Title);
}
};
await Task.Delay(1000);
// close modal1 in 5s
// this would automatically close modal2
var cts = new CancellationTokenSource(5000);
try
{
await modal1.ShowDialogAsync(cts.Token);
}
catch (OperationCanceledException)
{
Debug.WriteLine("Cancelled: " + modal1.Title);
}
}
}
/// <summary>
/// WindowExt
/// </summary>
public static class WindowExt
{
[ThreadStatic]
static CancellationToken s_currentToken = default(CancellationToken);
public static async Task<bool?> ShowDialogAsync(
this Window @this,
CancellationToken token = default(CancellationToken))
{
token.ThrowIfCancellationRequested();
var previousToken = s_currentToken;
using (var cts = CancellationTokenSource.CreateLinkedTokenSource(previousToken, token))
{
var currentToken = s_currentToken = cts.Token;
try
{
return await @this.Dispatcher.InvokeAsync(() =>
{
using (currentToken.Register(() =>
@this.Close(),
useSynchronizationContext: true))
{
try
{
var result = @this.ShowDialog();
currentToken.ThrowIfCancellationRequested();
return result;
}
finally
{
@this.Close();
}
}
}, DispatcherPriority.Normal, currentToken);
}
finally
{
s_currentToken = previousToken;
}
}
}
}
}
这允许您通过关联的 CancelationToken
取消最外层模态窗口,这将自动关闭任何嵌套模态窗口(那些使用 ShowDialogAsync
) 并退出相应的消息循环。因此,您的逻辑执行流将在正确的外部 消息循环中结束。
请注意,它仍然不能保证关闭多个模态窗口的正确逻辑顺序,如果这很重要的话。但它保证多个嵌套的 ShowDialogAsync
调用返回的任务将以正确的顺序完成。
关于c# - 关闭所有子 WPF 窗口并终止等待代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31616023/
有没有办法在另一个 WPF 窗口内托管 WPF 窗口。我有几个有点复杂的表格。但现在为了简化事情,我试图将其中一些合并为一个“仪表板”表单中的标签页。 请注意,我不是要托管 Windows 窗体,而是
WPF 特有的哪些方面和实践在非 WPF GUI 编程中最有用(并且并非难以实现)? 最佳答案 通过学习 WPF 命令,我了解了命令模式。它构成了 UI - 代码分离的基础,我认为应该在其他应用程序中
WinRT/Metro 正在获得一个新的 SemanticZoom控制,但我很难为 WPF 找到任何东西。 我不想为我的特定项目切换到 Metro,因为它不允许我制作窗口应用程序或跨多个显示器的多个实
我很难解决我的问题,我快要疯了。 想法是这样的:我有两个 ListView 元素,当一个元素从第一个列表掉落到第二个列表时,我需要打开一个对话,但我需要被掉落的元素的信息以及被添加以填充对话的元素。
如果我遵循TabControl,并且一切正常,当我切换到第二个Tabitem时,它显示就没有问题。 //datagrid //datagrid2 但是如果我有这个xaml,当我
在 Windows 窗体应用程序中,我们的数据 GridView 有很多事件,如行鼠标双击或行单击以及额外的...... 但是在 WPF 中我找不到这些事件。我如何将行鼠标双击添加到其中包含数据网格的
在这个项目中,代码 正确编译和执行 ;但是,我需要帮助解决两个问题: VS2012 WPF 设计器不适用于此 XAML 文件。它显示消息设计 View 对于 x64 和 ARM 目标平台不可用。 我收
目前我正在设计 WPF ScrollViewer,我发现了这个 Content="M 0 0 L 4 4 L 0 8 Z" 阅读 MSDN examples .现在我真的很想知道这意味着什么,但我无法
在 WPF 中,元素的可见性可以为“可见”,但实际上在屏幕上不可见,因为它的父元素(或父元素的父元素)具有折叠的可见性。 我希望能够知道一个元素是否实际呈现在屏幕上,而不必遍历可视化树检查父元素。 有
我应该使用 ApplicationCommands.Close用于关闭模式对话框还是该命令被认为是为关闭应用程序保留的?如果是后者,请大家创建Close每个命令 Dialog盒子或只是一个 Close
WPF 是否有任何可用的 piemenu 控件? 最佳答案 我在我的最爱中找到了这个,你可以看看: This 祝你今天过得愉快。 关于wpf - WPF 的菜单,我们在Stack Overflow上找
我正在尝试使用 WrapPanel 和两个 TextBlock 将星号 (*) 附加到某些文本的左侧,允许文本换行,并强制文本右对齐。通过创建一个 FlowDirection 设置为 RightToL
这里是场景(简化):我在Window上有一个控件(比如说一个Rectangle)。我迷上了MouseMove事件,以使其启动拖放操作。然后在MouseDown事件中进行动画处理,向右移动50个像素。但
我有一个 ListView ,它的项目来源是一个列表。我希望用户只选择一项。当我将 listview 的 SelectionMode 设置为 single 时,用户仍然可以选择多个项目,并且似乎 li
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the he
INotifyPropertyChanged 的目的是什么。我知道每当更改属性时都会触发此事件,但是 View /用户界面如何知道触发了此事件: 这是实现 INotifyPropertyChang
我正在查看工具箱中的 WPF 组件,但找不到 2005/2008 中存在的错误提供程序。 被移除了吗? 最佳答案 ErrorProvider是一个 Winforms 控件。 WPF 中没有等效项。但是
我试图在单击和双击 wpf Image 控件时有不同的行为。不幸的是,单击首先被触发,因此双击被忽略。 最佳答案 如果您改用 MouseDown 事件,则它在 EventArgs 中为 ClickCo
这可能吗? 我使用了一个框架控件并且:显示(例如:showwindow.xaml) 但是我得到这个错误: root element is not valid for navigation 最佳答案 确
我在蓝色背景的窗口上放置了一个扩展器,我想让扩展器的按钮与默认颜色不同(蓝色,它是从窗口接收的)。当我修改扩展器的背景属性时,它会将整个扩展器、标题和全部更改为新颜色。但是,我只想更改按钮本身。谁能指
我是一名优秀的程序员,十分优秀!