0

I have to unfortunately fire this window on a different thread than the main app. Then I am trying to update it every time a string input _html changes in my MakeWindow class.

Right now I am getting an error saying that I cannot execute this because I am calling it from a different thread that created it. How can i make it work here?

Is there a way to implement that event listener on the same thread that window exists? keep in mind that the _html will always be set and updated on the main thread. Ideas?

Thank you!

my classes:

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();
    }
}
}
konrad
  • 3,544
  • 4
  • 36
  • 75
  • Why are you spawning a new thread _just to open another window_, a **modal** one at that, anyway? Even if it is STA. I don't see the point and it's arguably bad design –  Sep 27 '15 at 01:45
  • 2
    possible duplicate of [C#: Updating GUI (WPF) using a different thread](http://stackoverflow.com/questions/4253088/c-updating-gui-wpf-using-a-different-thread) –  Sep 27 '15 at 01:48
  • @Roy I am running this from another application. That's why I need to keep them on separate threads because i want to allow user to keep working in the main app. – konrad Sep 27 '15 at 02:53
  • @Roy if there is a way to achieve this with a modeless window from the main thread then I am more than happy to listen to any suggestions. thanks in advance – konrad Sep 27 '15 at 02:55
  • @Konrad, I am not sure to figure eveything. Whodoes own the ReportPage property ? Is it modified from another thread ? If yes, the answer to your problem could be to change the "webbrowser.Navigate" line into "webBrowser.Dispatcher.Invoke( () => { webBrowser.NavigateToString((string)e.NewValue);} )" Regards – Emmanuel DURIN Sep 27 '15 at 07:49
  • No worries. Maybe make `DynamoWindow` modeless? –  Sep 27 '15 at 09:46

1 Answers1

1

I have uploaded a sample, extract and run : Browser

It also contains WinA, WinB windows. You can run WinA by changing in App.xaml. And see how WinB controls/properties are accessed/set by WinA.

  1. As you have posted half code as there is no code for how you are calling MakeWindow function, and how you have decided to bind and change ReportPage property. So, I have made a working solution. See the figure below :

Running sample

  1. I have changed your MakeWindow function.

  2. I have done some addition to your DynamoWindow code-behind.

MainWindow

<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 code-behind

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

Helper class for thread/window creation

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 codebehind class :

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));
        }
    }
}
AnjumSKhan
  • 9,647
  • 1
  • 26
  • 38