【发布时间】:2010-01-04 07:34:39
【问题描述】:
我在一个 XAML 窗口上放置了几个 ComboBox。当我展开其中任何一个时,DropDown 部分会出现在屏幕的左上角。
我使用 Visual Studio 2008 C# Express。我不记得我使用 Visual Studio 2008(试用版)时的这种现象,虽然我使用的是相同的 FrameWork (3.5)。
【问题讨论】:
-
给我们更多的细节和/或代码
我在一个 XAML 窗口上放置了几个 ComboBox。当我展开其中任何一个时,DropDown 部分会出现在屏幕的左上角。
我使用 Visual Studio 2008 C# Express。我不记得我使用 Visual Studio 2008(试用版)时的这种现象,虽然我使用的是相同的 FrameWork (3.5)。
【问题讨论】:
这似乎是一个错误。
解决方法:
使用Window.Show() 代替自定义逻辑来模拟ShowDialog() 行为。
【讨论】:
这似乎是 WPF 中的一个错误。就我而言,我试图在另一个窗口的 Loaded 事件中打开一个窗口。为了解决这个问题,我设置了一个计时器来触发,然后使用委托打开窗口(无法在计时器事件中打开窗口,因为打开窗口的调用线程必须是 STA)。
编辑 - 不需要计时器 - 没有看到上面的答案,只是在调度程序上排队...
private delegate void DelegateOpenWindow();
private DelegateOpenWindow m_DelegateOpenWindow;
private Timer loginTimer = new Timer(200);
private void MainWindow1_Loaded(object sender, RoutedEventArgs e)
{
// create delegate used for asynchronous call
m_DelegateOpenWindow= new DelegateOpenWindow(this.OpenWindow);
// start a timer to fire off the open window.
loginTimer.Elapsed += loginTimer_Elapsed;
loginTimer.Enabled = true;
}
void loginTimer_Elapsed(object sender, ElapsedEventArgs e)
{
loginTimer.Enabled = false;
this.Dispatcher.BeginInvoke(m_DelegateOpenWindow);
}
void OpenWindow()
{
MyWindow w = new MyWindow();
w.Owner = this;
w.ShowDialog();
}
【讨论】:
昨天,当我尝试“调整”窗口大小、形状、颜色并从 Window.Loaded 事件处理程序调用登录对话框时,我开始观察到这一点(以及其他奇怪的行为怪癖)。我在十几个单独的“MVVM”模式应用程序中都做得很好。昨天,我决定将其从每个应用程序的代码隐藏到一个统一的代码隐藏基类中,因为预处理已经在所有这些应用程序中变得普遍。当我这样做时,登录对话框中两个 ComboBoxes 中的下拉菜单突然出现在我的屏幕左上角。我似乎已经通过使用以下技术“解决”了它(您的里程可能会有所不同):
protected void WindowBaseLoadedHandler(object sender, RoutedEventArgs e)
{
...non-essential lines of code removed...
if (DataContext != null)
{
Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
{
/*----------------------------------------------------------------------
* Do we have a View Model? If so, perform standard VM Initialization...
*---------------------------------------------------------------------*/
this.IsEnabled = false;
LoginDlg loginDlg = new LoginDlg();
loginDlg.ShowDialog();
if (!loginDlg.Success)
{
/*-----------------------------------
* Log on failed -- terminate app...
*----------------------------------*/
...termination logic removed...
}
this.IsEnabled = true;
}));
}
WindowBaseLoadedHandler 是 Loaded 事件处理程序。 LoginDlg 是一个 WPF 应用程序,其中包含一个包含两个 ComboBox 的对话框。
回顾:在我将代码合并到基类的 Loaded 事件处理程序中后,ComboBox 的下拉列表出现在我屏幕的左上角。一旦我将逻辑包装到 Dispatcher.BeginInvoke 调用中,相应的 ComboBox 行为就会返回当前项下方的列表。
我怀疑 WPF 需要应用程序从 Loaded 事件返回以完成布局系统的初始化。这并不能完全解释为什么它以前有效,但我必须排好队,在未来的某个下雨天找到这个“为什么”,并庆祝今天克服了最新的障碍。
无论如何,我希望有人发现这个有用。
【讨论】:
我正在使用最新的 .Net 4.5 和 WPF 框架,但我仍然遇到这个问题。我注意到的一件事是,只有在附加调试器时才会发生这种情况。未附加调试器时,一切正常。
【讨论】:
我在 Visual Studio 2019 上遇到了同样的问题。 使用 window.Show() 会有所帮助,但会破坏您的设计。 解决方法是异步打开窗口。
var yourDialog= new YourDialog();
yourDialog.Owner = this;
TaskCompletionSource<bool?> completion = new TaskCompletionSource<bool?>();
this.Dispatcher.BeginInvoke(new Action(() =>
completion.SetResult(yourDialog.ShowDialog())));
bool? result = await completion.Task;
您还可以通过扩展方法创建更优雅的解决方案:
public static class AsyncWindowExtension
{
public static Task<bool?> ShowDialogAsync(this Window self)
{
if (self == null) throw new ArgumentNullException("self");
TaskCompletionSource<bool?> completion = new TaskCompletionSource<bool?>();
self.Dispatcher.BeginInvoke(new Action(() => completion.SetResult(self.ShowDialog())));
return completion.Task;
}
}
你可以这样使用它:
await dlgReview.ShowDialogAsync();
【讨论】:
这是 WPF 中的一个错误(恐怕不是唯一一个)。它发生在我在 Loaded Event 中打开另一个窗口时,例如:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
Window selectionWindow = new SelectionWindow();
bool? result = selectionWindow.ShowDialog();
if (result == true)
RecordChanged();
}
我已经找到了解决办法。
【讨论】:
Loaded 处理程序在Dispatcher 上排队另一条消息,该消息打开Window。