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.
–
–
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 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.