从C#(wpf)中的类返回一个对象

时间:2015-09-30 21:18:09

标签: c# wpf

我试图调用一个名为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()返回创建的窗口?

谢谢!

2 个答案:

答案 0 :(得分:1)

解决方案1:不在MainWindow中存储对NewWindow的引用。而是从MainWindow提升RefreshBrowser事件。 Dropbox link

解决方案2:在MainWindow中存储对NewWindow的引用: 新解决方案符合您的要求: Dropbox link

  1. 线程创建例程不等待ThreadProcedure运行,因此返回值始终为null。但是你可以在一些其他的事件处理程序中使用这个值。因为一旦这个例程完成,变量窗口将包含有效值。

  2. 然而,这不是你正在做的事情的正确方法。

  3. 今天的事件驱动编程世界有一种更清洁的方式。请记住,控件/窗口触发事件,我们访问发件人并使用相应的事件标记获取其他信息。例如;

    private void Window_Loaded(object sender, RoutedEventArgs e)

  4. 按照上述相同的模式,我们修改我们的代表,如下所示:

    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; }
    }
    
  5. ...

    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。除此之外,你为什么要尝试运行一个新的线程作为调度员;看一下调度程序运行方法。