我试图调用一个名为ThreadCreator()的类,然后调用其中一个名为CreateWindow()的方法,让它返回一个新创建的窗口,以便我可以在其他地方使用该对象来调用它上面的方法。
这是故障。我的线程创建者类在新线程上弹出一个新的wpf窗口:
using System;
using System.Threading;
using System.Diagnostics;
using System.IO;
using System.ComponentModel;
using System.Windows;
namespace Windamow
{
public static class ThreadCreator
{
private static NewWindow W;
public static NewWindow CreateWindow()
{
string appName = "";
try
{
appName = Path.GetFileName(System.Reflection.Assembly.GetEntryAssembly().Location);
const string IE_EMULATION = @"Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION";
using (var fbeKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(IE_EMULATION, true))
{
fbeKey.SetValue(appName, 9000, Microsoft.Win32.RegistryValueKind.DWord);
}
}
catch (Exception ex)
{
MessageBox.Show(appName + "\n" + ex.ToString(), "Unexpected error setting browser mode!");
}
Thread t = new Thread(ThreadProc);
t.SetApartmentState(ApartmentState.STA);
t.Start();
return W;
}
private static void ThreadProc(object obj)
{
W = new NewWindow();
W.ShowDialog();
}
}
}
New Window.xaml.cs如下所示:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace Windamow
{
/// <summary>
/// Interaction logic for NewWindow.xaml
/// </summary>
public partial class NewWindow : Window
{
string _message;
public string Message
{
get { return _message; }
set
{
_message = value;
this.Dispatcher.Invoke(() => { this.webBrowser.NavigateToString(_message); });
}
}
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
IntPtr _handle;
public IntPtr Handle { get { return _handle; } }
int _pid;
public int PID { get { return _pid; } }
public NewWindow()
{
InitializeComponent();
}
private void Window_Closed(object sender, EventArgs e)
{
WindowNotifier.OnIamClosed(Handle);
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
WindowNotifier.OnIamClosing(Handle);
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
_pid = Process.GetCurrentProcess().Id;
_handle = GetForegroundWindow();
WindowNotifier.OnIamCreated(Handle);
}
}
}
每次运行名为CheckIfWindowOpen()的方法时,我尝试对窗口执行的操作都会调用NavigateToString()方法。它基本上会检查窗口是否打开并打开它并执行NavigateToString(),否则它只会执行带有可能新输入(刷新)的NavigateToString()。
以下是我如何称呼它:
namespace Windamow
{
public class Win32F
{
[DllImport("user32.dll")]
public static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
}
public class DynamoDataVizNodes
{
[DllImport("user32.dll", SetLastError = true)]
public static extern int GetLastError();
// test html string
public static string HTMLString = "<html></html>";
IntPtr HandleOfWindowOnNewThread;
void WindowNotifier_IamCreatedEvent(IntPtr handle)
{
HandleOfWindowOnNewThread = handle;
Debug.WriteLine(string.Format("I am created : {0}", handle));
}
void WindowNotifier_IamClosedEvent(IntPtr handle)
{
if (HandleOfWindowOnNewThread == handle)
HandleOfWindowOnNewThread = IntPtr.Zero;
Debug.WriteLine(string.Format("I am closed : {0}", handle));
}
void WindowNotifier_IamClosingEvent(IntPtr handle)
{
Debug.WriteLine(string.Format("I am closing : {0}", handle));
}
public static NewWindow window;
public void CheckIfWindowOpen(string SourceString)
{
WindowNotifier.IamClosingEvent += WindowNotifier_IamClosingEvent;
WindowNotifier.IamClosedEvent += WindowNotifier_IamClosedEvent;
WindowNotifier.IamCreatedEvent += WindowNotifier_IamCreatedEvent;
if (HandleOfWindowOnNewThread == IntPtr.Zero)
{
// create new window and set browser
window = ThreadCreator.CreateWindow();
window.Dispatcher.Invoke(() => { window.webBrowser.NavigateToString(SourceString); });
}
else
{
// only set browser
window.Dispatcher.Invoke(() => { window.webBrowser.NavigateToString(SourceString); });
}
}
}
}
当我尝试返回一个NewWindow对象然后在其上调用NavigateToString()方法时,在CheckIfWindowOpen()方法中发生错误。它基本上返回null。有没有办法让ThreadCreator.CreateWindow()返回创建的窗口?
谢谢!
答案 0 :(得分:1)
解决方案1:不在MainWindow中存储对NewWindow的引用。而是从MainWindow提升RefreshBrowser事件。 Dropbox link
解决方案2:在MainWindow中存储对NewWindow的引用: 新解决方案符合您的要求: Dropbox link
线程创建例程不等待ThreadProcedure运行,因此返回值始终为null。但是你可以在一些其他的事件处理程序中使用这个值。因为一旦这个例程完成,变量窗口将包含有效值。
然而,这不是你正在做的事情的正确方法。
今天的事件驱动编程世界有一种更清洁的方式。请记住,控件/窗口触发事件,我们访问发件人并使用相应的事件标记获取其他信息。例如;
private void Window_Loaded(object sender, RoutedEventArgs e)
按照上述相同的模式,我们修改我们的代表,如下所示:
public static class WindowNotifier2
{
public static event CreatedDelegateCallback IamCreatedEvent;
public delegate void CreatedDelegateCallback(object sender, WindowNotifierEventArgs args);
public static event ClosingDelegateCallback IamClosingEvent;
public delegate void ClosingDelegateCallback(object sender, WindowNotifierEventArgs args);
public static event ClosedDelegateCallback IamClosedEvent;
public delegate void ClosedDelegateCallback(object sender, WindowNotifierEventArgs args);
public static void OnIamCreated(object sender, WindowNotifierEventArgs args)
{
if (IamCreatedEvent != null)
IamCreatedEvent(sender, args);
}
public static void OnIamClosing(object sender, WindowNotifierEventArgs args)
{
if (IamClosingEvent != null)
IamClosingEvent(sender, args);
}
public static void OnIamClosed(object sender, WindowNotifierEventArgs args)
{
if (IamClosedEvent != null)
IamClosedEvent(sender, args);
}
}
public class WindowNotifierEventArgs : EventArgs
{
public IntPtr WindowHandle { get; set; }
}
...
NewWindow.xaml.cs
private void Window_Loaded(object sender, RoutedEventArgs e)
{
_pid = Process.GetCurrentProcess().Id;
_handle = GetForegroundWindow();
WindowNotifier2.OnIamCreated(this, new WindowNotifierEventArgs() { WindowHandle = _handle });
}
MainWindow.xaml.cs
private void btnCheckNewWindow_Click(object sender, RoutedEventArgs e)
{
if (HandleOfWindowOnNewThread == IntPtr.Zero)
{
WindowNotifier2.IamCreatedEvent += (object source, WindowNotifierEventArgs args) =>
{
_newWindow = (NewWindow)source;
HandleOfWindowOnNewThread = args.WindowHandle;
Debug.WriteLine(string.Format("I am created : {0}", args.WindowHandle));
_newWindow.tbMsgFromMainWindow.Dispatcher.InvokeAsync(() => {
_newWindow.tbMsgFromMainWindow.Text = "I created you ! I am your creator.";
});
};
ThreadCreator.CreateWindow();
}
else
{
_newWindow.tbMsgFromMainWindow.Dispatcher.InvokeAsync(() => {
_newWindow.tbMsgFromMainWindow.Text = "I can see you are already running !";
});
}
}
答案 1 :(得分:0)
W只在另一个线程上设置,当你返回W时,它最像仍然是null。除此之外,你为什么要尝试运行一个新的线程作为调度员;看一下调度程序运行方法。