0

I used a those article to create AttachedProperty of Webbrowser control, so I can bind the “BindableSource” to my public property “Path”. It is great and work well with one small disadvantage. In my ViewModel constructor the property is set to:

Path = new Uri("http://microsoft.com");

When the page is loaded I navigate to another link and “WebBrowser.Source” property is changed but “WebBrowser.BindableSource” is not changed. When I click a button which set again:

 Path = new Uri("http://microsoft.com");

The “BindableSourcePropertyChanged” is not called because the property has those value.

I had an idea how to solve it but its not good, because slow the performance, It is to set Path to another URL and after that set it to real URL (http://microsoft.com).

   Path = new Uri("http://google.com");
   Path = new Uri("http://microsoft.com");

Can you give me please a better idea, how can I solved it. Thanks in advanced.

Community
  • 1
  • 1
Tiho
  • 123
  • 2
  • 8

1 Answers1

2

I propose to synchronize BindableSource with Navigated event. You coukld achieve this by exposing another one attached behaviour at your WebBrowserUtility class, that reacts on Navigated event like this:

    public static readonly DependencyProperty ShouldHandleNavigatedProperty =
        DependencyProperty.RegisterAttached(
            "ShouldHandleNavigated", 
            typeof(Boolean), 
            typeof(WebBrowserUtility), 
            new UIPropertyMetadata(false, ShouldHandleNavigatedPropertyChanged));

    public static Boolean GetShouldHandleNavigated(DependencyObject obj)
    {
        return (Boolean)obj.GetValue(BindableSourceProperty);
    }

    public static void SetShouldHandleNavigated(DependencyObject obj, Boolean value)
    {
        obj.SetValue(ShouldHandleNavigatedProperty, value);
    }

    public static void ShouldHandleNavigatedPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
    {
        WebBrowser browser = o as WebBrowser;
        if (browser != null)
        {
            if ((bool)e.NewValue)
            {
                browser.Navigated += new NavigatedEventHandler(Browser_Navigated);
            }
            else
            {
                browser.Navigated -= new NavigatedEventHandler(Browser_Navigated);
            }
        }
    }

    private static void Browser_Navigated(object sender, NavigationEventArgs e)
    {
        WebBrowser browser = sender as WebBrowser;
        if (browser != null)
        {
            browser.SetValue(WebBrowserUtility.BindableSourceProperty, browser.Source.AbsoluteUri);
        }
    }

Usage in xaml:

<WebBrowser self:WebBrowserUtility.BindableSource="{Binding WebAddress}"
            self:WebBrowserUtility.ShouldHandleNavigated="True"/>  

P.S. I should admit that this implementation is rather dirty, because setting of BindableSource inside Navigated event handler forces one additional event fireing. But this code works, and you could consider about its improvement.

EDITED

    public static class WebBrowserUtility
    {
        ...
        private const string _SkipSourceChange = "Skip";

        public static void BindableSourcePropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            WebBrowser browser = o as WebBrowser;
            if (browser != null)
            {
                string uri = e.NewValue as string;
                if (!_SkipSourceChange.Equals(browser.Tag))
                {
                    browser.Source = uri != null ? new Uri(uri) : null;
                }
            }
        }

        private static void Browser_Navigated(object sender, NavigationEventArgs e)
        {
            WebBrowser browser = sender as WebBrowser;
            if (browser != null)
            {
                if (WebBrowserUtility.GetBindableSource(browser) != e.Uri.ToString())
                {
                        browser.Tag = _SkipSourceChange;
                        browser.SetValue(WebBrowserUtility.BindableSourceProperty, browser.Source.AbsoluteUri);
                        browser.Tag = null;
                }
            }
        }
    }
Alex Zhevzhik
  • 3,347
  • 19
  • 19
  • Thanks Mate, your solution is error free and works but cannot solve my problem, because on some page I use a POST request. It is navigating to the same page twice, so when navigated complete BindableSourcePropperty is changed and webbrowser navigate to the same page. In case I used a Post request I get trouble. But thanks in some case it can be useful. – Tiho Feb 08 '11 at 09:23
  • Actually, I've admitted this problem in P.S. I've just proposed you to turn imagination on and solve this problem by yourelf. Solution is obvious: inside Browser_Navigated handler before browser.SetValue(...) you should set some flag and immidiately after browser.SetValue(...) reset it. Then in BindableSourcePropertyChanged handler if this flag is setted you should skip changing of BindableSourceProperty. The right way is exposing another one attached property, but in my sample above I achieve expected result with Tag property. – Alex Zhevzhik Feb 08 '11 at 10:51