我找到了这个解决方案,用于检查窗口是否打开:
How do I know if a WPF window is opened
因为我的wpf窗口在另一个线程上,所以它向我抛出一个错误。有没有办法继续使用它?
解决方案:
**data dump**
defaultdict(<class 'list'>, {<BadgeType: Talent>: [<BadgeAssertion: Blender Blue Belt>], <BadgeType: Achievement>: [<BadgeAssertion: MyBadge#1>, <BadgeAssertion: MyBadge#1>, <BadgeAssertion: MyBadge#2>], <BadgeType: Award>: [<BadgeAssertion: Copy of Copy of Blenbade>]})
**dataitems**
Talent: [<BadgeAssertion: Blender Blue Belt>]
Achievement: [<BadgeAssertion: MyBadge#1>, <BadgeAssertion: MyBadge#1>, <BadgeAssertion: MyBadge#2>]
Award: [<BadgeAssertion: Copy of Copy of Blenbade>]
**data.items**
**Not found test**
DEBUG WARNING: undefined template variable [i_dont_exist] not found
答案 0 :(得分:2)
我已经创建了一个示例应用程序,可以在花了一整天后解决您的问题。
Solution can be downloaded here
它的作用: 单击按钮在新线程上创建窗口。在新线程上为您创建一个新窗口。创建此新窗口时,主窗口中的此按钮将被禁用。当您关闭新窗口时,主窗口中的创建按钮将再次启用。
如果它不符合您的需求,请告诉您的要求,我会改进它。使用纯Win32函数也可以完成相同的操作,而无需使用我们的事件桥类。我正在做。我很快就会发布win32版本。
使用的Win32函数:
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
public static extern bool IsWindowVisible(IntPtr hWnd);
ThreadCreator.cs
public static class ThreadCreator
{
private static NewWindow W;
public static void CreateWindow()
{
Thread t = new Thread(ThreadProc);
t.SetApartmentState(ApartmentState.STA);
t.Start();
}
private static void ThreadProc(object obj)
{
W = new NewWindow();
W.ShowDialog();
}
}
WindowNotifier.cs
public static class WindowNotifier
{
public static event CreatedDelegateCallback IamCreatedEvent;
public delegate void CreatedDelegateCallback(IntPtr handle);
public static event ClosingDelegateCallback IamClosingEvent;
public delegate void ClosingDelegateCallback (IntPtr handle);
public static event ClosedDelegateCallback IamClosedEvent;
public delegate void ClosedDelegateCallback(IntPtr handle);
public static void OnIamCreated(IntPtr handle)
{
if (IamCreatedEvent != null)
IamCreatedEvent(handle);
}
public static void OnIamClosing(IntPtr handle)
{
if (IamClosingEvent != null)
IamClosingEvent(handle);
}
public static void OnIamClosed(IntPtr handle)
{
if (IamClosedEvent != null)
IamClosedEvent(handle);
}
}
MainWindow.xaml.cs
...
void WindowNotifier_IamCreatedEvent(IntPtr handle)
{
HandleOfWindowOnNewThread = handle;
Debug.WriteLine(string.Format("I am created : {0}", handle));
btnCreateNewWindow.Dispatcher.Invoke(() => btnCreateNewWindow.IsEnabled = false);
}
void WindowNotifier_IamClosedEvent(IntPtr handle)
{
if (HandleOfWindowOnNewThread == handle)
HandleOfWindowOnNewThread = IntPtr.Zero;
Debug.WriteLine(string.Format("I am closed : {0}", handle));
btnCreateNewWindow.Dispatcher.Invoke(() => btnCreateNewWindow.IsEnabled = true);
}
...
NewWindow.xaml.cs
...
private void Window_Closed(object sender, EventArgs e)
{
WindowNotifier.OnIamClosed(Handle);
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
WindowNotifier.OnIamClosing(Handle);
}
// To get correct handle we need to ensure Window is fully created and active
private void Window_Loaded(object sender, RoutedEventArgs e)
{
_handle = GetForegroundWindow();
WindowNotifier.OnIamCreated(Handle);
}
...
答案 1 :(得分:1)
Dispatcher在这里没有帮助,因为当在另一个线程上创建窗口时,它不包含在Application.Windows
集合中,而是包含在由于某种原因未被暴露的集合中(称为{{3 }})。很快,没有正式的方法可以做到这一点。当然,您可以根据自己的风险使用反思。
但是如果你的窗口在UI线程上并且你只想从另一个线程调用该函数,那么你可以使用这样的东西
Application.Current.Dispatcher.Invoke(() => IsWindowOpen<...>(...))
或更好地将辅助方法更改为
public static bool IsWindowOpen<T>(string name = "") where T : Window
{
return Application.Current.Dispatcher.Invoke(() => string.IsNullOrEmpty(name)
? Application.Current.Windows.OfType<T>().Any()
: Application.Current.Windows.OfType<T>().Any(w => w.Name.Equals(name)));
}
编辑以下是目前有效的内容,但未来可能会发生变化,如上所述,请自行承担风险
public static class WindowUtils
{
public static bool IsWindowOpen<T>(string name = "") where T : Window
{
return FindWindow<T>(name) != null;
}
public static T FindWindow<T>(string name = "") where T : Window
{
return FindWindow<T>(WindowsInternal, name) ?? FindWindow<T>(NonAppWindowsInternal, name);
}
private static T FindWindow<T>(Func<Application, WindowCollection> windowListAccessor, string name = "") where T : Window
{
bool matchName = !string.IsNullOrEmpty(name);
var windowList = windowListAccessor(Application.Current);
for (int i = windowList.Count - 1; i >= 0; i--)
{
var window = windowList[i] as T;
if (window != null && (!matchName || window.Name == name)) return window;
}
return null;
}
private static readonly Func<Application, WindowCollection> WindowsInternal = GetWindowCollectionAccessor("WindowsInternal");
private static readonly Func<Application, WindowCollection> NonAppWindowsInternal = GetWindowCollectionAccessor("NonAppWindowsInternal");
private static Func<Application, WindowCollection> GetWindowCollectionAccessor(string propertyName)
{
var property = typeof(Application).GetProperty(propertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
return (Func<Application, WindowCollection>)Delegate.CreateDelegate(
typeof(Func<Application, WindowCollection>), property.GetMethod);
}
}
答案 2 :(得分:0)
如果您从IsWindowOpen
方法返回窗口。你可以使用窗口上的Invoke
或BeginInvoke
来分配创建窗口的线程上的工作。