从不同的线程

时间:2015-09-27 01:14:44

标签: c# wpf multithreading xaml thread-safety

不幸的是,我必须在与主应用程序不同的线程上触发此窗口。然后我每次在MakeWindow类中更改字符串输入_html时都尝试更新它。

现在我收到错误,说我无法执行此操作,因为我是从创建它的其他线程调用它。我怎样才能在这里工作?

有没有办法在窗口存在的同一个线程上实现该事件监听器?请记住,_html将始终在主线程上设置和更新。想法?

谢谢!

我的班级:

namespace Windamow
{
public static class WebBrowserUtility
{
    public static readonly DependencyProperty BindableSourceProperty =
                           DependencyProperty.RegisterAttached("BindableSource", typeof(string),
                           typeof(WebBrowserUtility), new UIPropertyMetadata(null,
                           BindableSourcePropertyChanged));

    public static string GetBindableSource(DependencyObject obj)
    {
        return (string)obj.GetValue(BindableSourceProperty);
    }

    public static void SetBindableSource(DependencyObject obj, string value)
    {
        obj.SetValue(BindableSourceProperty, value);
    }

    public static void BindableSourcePropertyChanged(DependencyObject o,
                                                     DependencyPropertyChangedEventArgs e)
    {
        var webBrowser = (WebBrowser)o;
        webBrowser.NavigateToString((string)e.NewValue);
    }
}


public class Windamow
{

    private DynamoWindow window;
    public static string html;

    internal void ThreadProc()
    {
        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!");
        }

        window = new DynamoWindow();
        window.ShowDialog();
    }

    internal Windamow()
    {
        Thread t = new Thread(ThreadProc);
        t.SetApartmentState(ApartmentState.STA);
        t.Start();
    }

    /// <summary>
    /// asd
    /// </summary>
    /// <param name="launch"></param>
    /// <param name="_html"></param>
    /// <returns></returns>
    public static DynamoWindow MakeWindow(bool launch, string _html)
    {
        if (launch)
        {
            if (MyProject.Utility.WebBrowserUtility.IsWindowOpen<Window>("MainWindow"))
            {
                html = _html;
                return null;
            }
            else
            {
                html = _html;
                Windamow mow = new Windamow();
                return mow.window;
            } 
        }
        else
        {
            return null;
        }
    }
}
}

XAML:

<Window x:Class="Windamow.DynamoWindow"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d"
         xmlns:ns="clr-namespace:Windamow"
         Title="MainWindow"
         d:DesignHeight="300" d:DesignWidth="300">
<Grid>
    <!--<WebBrowser x:Name="browser" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>-->
    <WebBrowser x:Name="browser" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ns:WebBrowserUtility.BindableSource="{Binding ReportPage}"/>
</Grid>

xaml.cs:

namespace Windamow
{
/// <summary>
/// Interaction logic for DynamoWindow.xaml
/// </summary>
public partial class DynamoWindow : Window
{
    public DynamoWindow()
    {
        InitializeComponent();
    }
}
}

1 个答案:

答案 0 :(得分:1)

我上传了一个样本,提取并运行: Browser

它还包含WinA,WinB窗口。您可以通过在App.xaml中更改来运行WinA。并了解WinA如何访问/设置WinB控件/属性。

  1. 由于您没有调用MakeWindow函数的代码,以及如何决定绑定和更改ReportPage属性,因此您发布了一半代码。所以,我已经制定了一个有效的解决方案见下图:
  2. Running sample

    1. 我更改了您的MakeWindow功能。

    2. 我为您的DynamoWindow代码隐藏做了一些补充。

    3. 主窗口

      <Window x:Class="Windamow.Win32803621"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              Title="Win32803621" Height="300" Width="300">
          <Grid>
              <Grid.RowDefinitions>
                  <RowDefinition Height="42*"/>
                  <RowDefinition Height="79*"/>
                  <RowDefinition Height="149*"/>
              </Grid.RowDefinitions>
              <Button x:Name="btnCreateAndOpen" Content="Create browser on new thread" HorizontalAlignment="Left" Margin="67,10,0,0" VerticalAlignment="Top" Click="btnCreateAndOpen_Click"/>
              <TextBox x:Name="tbHtmlInput" HorizontalAlignment="Left" Height="59" Margin="10,10,0,0" Grid.Row="1" TextWrapping="Wrap" VerticalAlignment="Top" Width="272" AcceptsReturn="True" AcceptsTab="True"/>
              <Button x:Name="btnUpdateBrowser" Content="Update browser" HorizontalAlignment="Left" Margin="88,10,0,0" Grid.Row="2" VerticalAlignment="Top" Width="98" Click="btnUpdateBrowser_Click"/>
      
          </Grid>
      </Window>
      

      MainWindow代码隐藏

      using System;
      using System.Windows;
      using System.Windows.Controls;
      
      namespace Windamow
      {
          /// <summary>
          /// Interaction logic for Win32803621.xaml
          /// </summary>
          public partial class Win32803621 : Window
          {
              public Win32803621()
              {
                  InitializeComponent();
                  tbHtmlInput.Text = "<a href='http://www.stackoverflow.com'>Click to open StackOverflow.com</a>";
              }
      
              DynamoWindow browserWindow;
      
              private void btnCreateAndOpen_Click(object sender, RoutedEventArgs e)
              {
                  Windamow.MakeWindow(true, tbHtmlInput.Text);
              }
      
              private void btnUpdateBrowser_Click(object sender, RoutedEventArgs e)
              {
                  browserWindow = Windamow.window;
                  browserWindow.ReportPage = tbHtmlInput.Text;
              }
          }
      }
      

      创建线程/窗口的助手类

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;
      using System.ComponentModel;
      using System.Windows;
      using System.Windows.Controls;
      using System.Threading;
      using System.IO;
      
      namespace Windamow
      {
          public static class WebBrowserUtility
          {
              public static readonly DependencyProperty BindableSourceProperty =
                                     DependencyProperty.RegisterAttached("BindableSource", typeof(string),
                                     typeof(WebBrowserUtility), new UIPropertyMetadata(null,
                                     BindableSourcePropertyChanged));
      
              public static string GetBindableSource(DependencyObject obj)
              {
                  return (string)obj.GetValue(BindableSourceProperty);
              }
      
              public static void SetBindableSource(DependencyObject obj, string value)
              {
                  obj.SetValue(BindableSourceProperty, value);
              }
      
              public static void BindableSourcePropertyChanged(DependencyObject o,
                                                               DependencyPropertyChangedEventArgs e)
              {
                  WebBrowser webBrowser = (WebBrowser)o;
                  webBrowser.NavigateToString((string)e.NewValue);
              }
          }
      
      
          public class Windamow
          {
              public static DynamoWindow window;
      
              public static string html;
      
              internal void ThreadProc()
              {
                  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!");
                  }
      
                  window = new DynamoWindow();
                  window.ShowDialog();
              }
      
              internal Windamow()
              {
                  Thread t = new Thread(ThreadProc);
                  t.SetApartmentState(ApartmentState.STA);
                  t.Start();
              }
      
              /// <summary>
              /// asd
              /// </summary>
              /// <param name="launch"></param>
              /// <param name="_html"></param>
              /// <returns></returns>
              public static void MakeWindow(bool launch, string _html)
              {
                  Windamow mow = new Windamow();
                  //return mow.window;
      
                  //if (launch)
                  //{
                  //    if (MyProject.Utility.WebBrowserUtility.IsWindowOpen<Window>("MainWindow"))
                  //    {
                  //        html = _html;
                  //        return null;
                  //    }
                  //    else
                  //    {
                  //        html = _html;
                  //        Windamow mow = new Windamow();
                  //        return mow.window;
                  //    }
                  //}
                  //else
                  //{
                  //    return null;
                  //}
              }
          }
      }
      

      DynamoWindow代码隐藏类:

      namespace Windamow
      {
          /// <summary>
          /// Interaction logic for DynamoWindow.xaml
          /// </summary>
          public partial class DynamoWindow : Window, INotifyPropertyChanged
          {
              private String _reportPage;
              public String ReportPage { get { return _reportPage; } set { _reportPage = value; OnPropertyChanged("ReportPage"); } }
      
              public DynamoWindow()
              {
                  InitializeComponent();
      
                  browser.DataContext = this;
              }
      
              public event PropertyChangedEventHandler PropertyChanged;
              public void OnPropertyChanged(String propName)
              {
                  if (PropertyChanged != null)
                      PropertyChanged(this, new PropertyChangedEventArgs(propName));
              }
          }
      }