wpf - DependencyProperty.RegisterAttached 和多个实例

标签 wpf mvvm dependency-properties

我正在开发一个 WPF MVVM 应用程序。我正在寻找将 WebBrowser 控件数据绑定(bind)到 View 模型,该 View 模型又绑定(bind)到选项卡。遵循 article 中的建议,我创建了一个由静态 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 将 WebBrowser 绑定(bind)到 DependancyProperty:
<WebBrowser Grid.Column="2" HorizontalAlignment="Center" src:WebBrowserHelper.Body="{Binding HTMLBody}"  VerticalAlignment="Center" Height="Auto" Width="Auto"  />

绑定(bind)到 Tab Control 的 ItemsSource 的 ViewModel:
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; }
        set
        {
            if (_htmlBody != value)
            {
                _htmlBody = value;
                RaisePropertyChanged("HTMLBody");
            }
        }
    }

    public SomeView View
    {
        get {return _myView;}
        set { }
    }

    public string TabName { get; set; }
}

MainViewModel,创建 Tab 集合:
    private ObservableCollection<SomeVM> _tabs;
    public ObservableCollection<SomeVM> Tabs
    {
        get
        {
            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 设置选项卡绑定(bind):
           <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>

我的问题是“OnBodyChanged”在标签更改时被多次触发。 HTML 需要几秒钟来加载,我宁愿它只在 View 模型中实际修改属性时加载。

编辑

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

最佳答案

您的问题与附加属性或 MVVM 无关。
事实上,真正的问题是 TabControl 每次更改所选选项卡时都会破坏并重新创建其子项。这可以解释为什么处理程序被多次调用。 VisualTree 仅包含选定的选项卡。

如果您可以尝试使用其他控件,您将看到没有错误。

为了解决这个问题,我会把你重定向到这个 post .

关于wpf - DependencyProperty.RegisterAttached 和多个实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12691328/

相关文章:

c# - 带集合的 MVVM 模型。在模型中使用或不使用 observablecollection

c# - 将多个属性元数据添加到工作流事件中的依赖属性

wpf - MVVM + UserControl + 依赖属性

c# - 在 LiveChart 中自定义起始索引

c# - 依赖属性绑定(bind)和更新到自定义控件——它更新,但显然不是两种方式?

c# - 如何使 WPF 窗口位于我的应用程序的所有其他窗口之上(不是系统范围的)?

c# - 为wpf mvvm应用程序设置字体系列的用户首选项

wpf - TemplatePart发现

mvvm - Prism/mvvm : how to bind GotFocus of View to an action?

c# - 如何在代码中读取对象的 DependencyProperty?