2015-09-30 3 views
0

Я пытаюсь вызвать класс ThreadCreator(), а затем один из его методов, называемый CreateWindow(), и вернуть ему новое окно, которое оно создало, чтобы я мог использовать этот объект где-нибудь еще, чтобы вызвать метод на нем.Возвращение объекта из класса в C# (wpf)

Прорыв. Мой поток создатель класс, который выскакивает новое окно 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(); 
    } 
} 
} 

Нового 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); 
    } 
} 
} 

То, что я пытаюсь сделать с окном вызова метод NavigateToString() каждый раз, когда запускается метод, называемый CheckIfWindowOpen(). Он будет в основном проверять, открыто ли окно, либо открыть его, либо выполнить 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); }); 
     } 
    } 
} 
} 

ошибка происходит в методе CheckIfWindowOpen(), когда я пытаюсь вернуть объект NewWindow в то вызывается метод NavigateToString() на нем. Он в основном возвращает null. Есть ли способ сделать ThreadCreator.CreateWindow() вернуть созданное окно?

Спасибо!

+0

кстати огромное спасибо @AnjumSKhan (http://stackoverflow.com/users/3667257/anjumskhan) для первоначальной помощи. Я просто делаю небольшие изменения, чтобы он соответствовал моей конкретной потребности. – konrad

ответ

1

Решение1: без сохранения ссылки на NewWindow в MainWindow. Вместо этого вызывается событие RefreshBrowser из MainWindow. Dropbox link

Solution2: Сохранение ссылки на NewWindow в MainWindow: Новое решение изменено с вашими требованиями: процедура создания Dropbox link

  1. Автор не ждать ThreadProcedure бежать, поэтому возвращаемое значение будет нулевым всегда. Но вы можете использовать это значение в некотором другом обработчике событий. Поскольку после завершения этой процедуры переменное окно будет содержать допустимое значение.

  2. Однако это неправильный способ сделать то, что вы пытаетесь сделать.

  3. В современном мире программирования, управляемом событиями, есть более чистый способ. Помните, события управления огнем/окна, и мы получаем доступ к отправителю и получаем дополнительную информацию с помощью соответствующих eventargs. Например;

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

...

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 !"; 
       }); 
      } 
     } 
+0

ты гений! Именно этого я и надеялся. Мне очень нравится первый метод. Отлично! Еще раз спасибо! – konrad

+0

@konrad С решением 1 мы получаем доступ к элементу управления, присутствующему в NewWindow, с помощью диспетчера, который мне не нравится. Элемент управления, присутствующий в окне, должен быть доступен обычным образом. Я работаю над удалением вещи диспетчера полностью в решении 1. – AnjumSKhan

+0

да, если у вас есть лучшие идеи, то я слушаю :-) отличная работа. Спасибо. – konrad

0

W установлен только в другом потоке, и когда вы возвращаете W, это больше всего равно null. Кроме того, почему вы пытаетесь запустить новый поток в качестве диспетчера; взгляните на метод запуска диспетчера.

Смежные вопросы