如何在不违反MVVM的情况下在视图中创建控件的新实例

时间:2012-04-17 06:06:37

标签: wpf silverlight mvvm

我遇到的问题与in this SO question所描述的类似。建议的解决方案是为我们希望呈现的每个现在页面(PDF)创建一个新的WebBrowser控件(覆盖旧的WebBrowser控件)。 在MVVM中创建新控件的正确方法是什么?我试图让VM无视视图的实现。

3 个答案:

答案 0 :(得分:1)

为什么VM需要知道?为什么视图不能挂钩到适当的事件(如果你愿意定义一个,或者只是使用PropertyChanged)并重新创建控件?

答案 1 :(得分:1)

  1. 使用名为CreateBrowser()的方法在名为IBrowserCreator的ViewModel中创建一个接口。
  2. 在名为ViewHelper的ViewModel中创建一个静态类,并向其添加名为BrowserCreator的IBrowserCreator类型的静态属性。
  3. 在View层中,创建一个名为BrowserCreator的新类,该类实现ViewModel.IBrowserCreator。
  4. 在View初始化代码中,实例化BrowserCreator,并将其分配给ViewModel.ViewHelper.BrowserCreator。
  5. 现在,您应该可以从ViewModel调用:

    ViewHelper.BrowserCreator.CreateBrowser()

    显然这个答案只是一个框架,但它应该给你一般的想法。您需要实现CreateBrowser方法以满足您的确切需求。

答案 2 :(得分:0)

为什么不简单地使用Datatemplate让WPF完成剩下的工作呢?

  1. 使用webbrowser创建用户控件。您必须添加附加属性,因为您无法直接绑定到源。

    <UserControl x:Class="WpfBrowser.BrowserControl"
             xmlns:WpfBrowser="clr-namespace:WpfBrowser" >
      <Grid>
        <WebBrowser WpfBrowser:WebBrowserUtility.BindableSource="{Binding MyPdf}"/>
      </Grid>
    </UserControl>
    
  2. 创建一个处理你的uri的viewmodel

    public class MyPdfVM
    {
      public Uri MyPdf { get; set; }
    
      public MyPdfVM()
      {
        this.MyPdf = new Uri(@"mypdf path"); 
      }
    }
    
  3. 获取您的pageviewmodel,添加pdfviewmodel并在视图中获取内容控件

    public class MyPageViewmodel: INotifyPropertyChanged
    {
      private MyPdfVM _myPdfStuff;
      public MyPdfVM MyPdfStuff
      {
        get { return _myPdfStuff; }
        set { _myPdfStuff = value; this.NotifyPropertyChanged(()=>this.MyPdfStuff);}
      }
    
      public MyViewmodel()
      {
        this.MyPdfStuff = new MyPdfVM();
      }
    
      public event PropertyChangedEventHandler PropertyChanged;
      protected void NotifyPropertyChanged<T>(Expression<Func<T>> property)
      {
        var propertyInfo = ((MemberExpression)property.Body).Member as PropertyInfo;
    
        if (propertyInfo == null)
        {
            throw new ArgumentException("The lambda expression 'property' should point to a valid Property");
        }
    
        var handler = PropertyChanged;
    
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyInfo.Name));
      }
    }
    
  4. window.xaml

        <Window x:Class="WpfBrowser.MainWindow"
                xmlns:WpfBrowser="clr-namespace:WpfBrowser" 
                Title="MainWindow" Height="350" Width="525">
         <Window.Resources>
           <DataTemplate DataType="{x:Type WpfBrowser:MyPdfVM}">
            <WpfBrowser:BrowserControl />
           </DataTemplate>
         </Window.Resources>
         <Grid>
           <Grid.RowDefinitions>
            <RowDefinition Height="64*" />
            <RowDefinition Height="247*" />
           </Grid.RowDefinitions>
          <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="32,14,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
          <ContentControl Grid.Row="1" Content="{Binding MyPdfStuff}"/>
         </Grid>
        </Window>
    

    window.xaml.cs

    public partial class MainWindow : Window
    {
        private MyViewmodel _data;
        public MainWindow()
        {
            _data = new MyViewmodel();
            InitializeComponent();
            this.DataContext = _data;
        }
    
        private void button1_Click(object sender, RoutedEventArgs e)
        {
            this._data.MyPdfStuff = new MyPdfVM() { MyPdf = new Uri(@"your other pdf path for testing") };
        }
    }
    

    当您更改MyPdfStuff属性时,webbroswer会更新pdf。

    附加财产

    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 browser = o as WebBrowser;
            if (browser != null)
            {
                string uri = e.NewValue as string;
                browser.Source = string.IsNullOrWhiteSpace(uri) ? null:new Uri(uri);
            }
        }
    
    }
    

    编辑:添加了一些代码,以便您可以看到,如果您使用PDFViewmodel,您的browsercontrol会显示新的pdf。