Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I'm working on a WPF MVVM application. I'm looking to databind a WebBrowser control to a view model which is in turn bound to a Tab. Following the advice in this article , I created a static helper class consisting of a static DependancyProperty:

public static class WebBrowserHelper
    public static readonly DependencyProperty BodyProperty =
        DependencyProperty.RegisterAttached("Body", typeof(string), typeof(WebBrowserHelper), new PropertyMetadata(OnBodyChanged));
    public static string GetBody(DependencyObject dependencyObject)
        return (string)dependencyObject.GetValue(BodyProperty);
    public static void SetBody(DependencyObject dependencyObject, string body)
        dependencyObject.SetValue(BodyProperty, body);
    private static void OnBodyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        string newValue = (string)e.NewValue;
        var webBrowser = (WebBrowser)d;
        webBrowser.NavigateToString(newValue);

XAML Binding WebBrowser to DependancyProperty:

<WebBrowser Grid.Column="2" HorizontalAlignment="Center" src:WebBrowserHelper.Body="{Binding HTMLBody}"  VerticalAlignment="Center" Height="Auto" Width="Auto"  />

ViewModel that bound to ItemsSource of Tab Control:

public class SomeVM : ViewModelBase, INotifyPropertyChanged
    private string _htmlBody;
    private SomeView _myView = new SomeView();
    public SomeVM (string tabName)
        TabName = tabName;
        string contentsAsHTML = do_a_whole_bunch_of_stuff_to_generate_an_HTML_string();
        HTMLBody = contentsAsHTML;
    public string HTMLBody
        get { return _htmlBody; }
            if (_htmlBody != value)
                _htmlBody = value;
                RaisePropertyChanged("HTMLBody");
    public SomeView View
        get {return _myView;}
        set { }
    public string TabName { get; set; }

MainViewModel, Creating the Tab collection:

    private ObservableCollection<SomeVM> _tabs;
    public ObservableCollection<SomeVM> Tabs
            if (_tabs== null)
                _tabs= new ObservableCollection<SomeVM>();
                _tabs.Add(new SomeVM("Tab 1"));
                _tabs.Add(new SomeVM("Tab 2"));
                _tabs.Add(new SomeVM("Tab 3"));
            return _tabs;

MainWindow.xaml setting up the Tab Binding:

           <TabControl ItemsSource="{Binding Tabs, Source={StaticResource vm}}"
                <TabControl.ItemTemplate>
                    <DataTemplate>
                        <TextBlock
                            Text="{Binding TabName}" />
                    </DataTemplate>
                </TabControl.ItemTemplate>
                <TabControl.ContentTemplate>
                    <DataTemplate>
                        <ContentPresenter Content="{Binding View}" />
                    </DataTemplate>
                </TabControl.ContentTemplate>
           </TabControl>

My problem is that "OnBodyChanged" is fired multiple times on ever tab change. The HTML takes a few seconds to load, and I would rather it only loads when the property is actually modified in the viewmodel.

Here's the smallest sample project that recreates my problem.

in fact the more interesting is not here... can you show how the viewmodel is binded to the view ? – Cybermaxs Oct 2, 2012 at 14:33 @Cybermaxs, the viewmodel is an observable collection which represents a collection of TabControl in the view. See above. Again, thanks. – Mark Oct 2, 2012 at 14:58

Your problem is not relevant to attached properties or MVVM. In fact, the real problem is that TabControl destroy and recreate its child every time you change the selected tab. That would explain why the handler is invoked more than once. The VisualTree only contains the selected Tab.

If you can try with another control, you will see there are no errors.

For solving this issue, I will redirect you to this post.

Thanks man. I'm new to MVVM so I was convinced I was screwing that up. You are absolutely correct, I just applied your linked fix and it worked like a charm. Shame on Microsoft for making controls behave like that. – Mark Oct 2, 2012 at 23:21

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.