我遇到了与此 SO question中描述的类似的问题。建议的解决方案是为我们希望呈现的每个现在页面 (PDF) 创建一个新的 WebBrowser 控件(覆盖旧的 WebBrowser 控件)。在 MVVM 中创建新控件的正确方法是什么?我试图让 VM 对视图的实现一无所知。
问问题
282 次
3 回答
1
为什么 VM 需要知道?为什么视图不能挂钩到一个适当的事件(如果你喜欢定义一个,或者只是使用PropertyChanged
)并重新创建控件?
于 2012-04-17T06:20:41.117 回答
1
- 在 ViewModel 中创建一个名为 IBrowserCreator 的接口,并使用一个名为 CreateBrowser() 的方法。
- 在 ViewModel 中创建一个名为 ViewHelper 的静态类,并向其添加一个名为 BrowserCreator 的 IBrowserCreator 类型的静态属性。
- 在 View 层中,创建一个名为 BrowserCreator 的新类,该类实现 ViewModel.IBrowserCreator。
- 在 View 初始化代码中,实例化一个 BrowserCreator,并将其分配给 ViewModel.ViewHelper.BrowserCreator。
从您的 ViewModel,您现在应该可以调用:
ViewHelper.BrowserCreator.CreateBrowser()
显然这个答案只是一个框架,但它应该给你一个大致的想法。您需要实现 CreateBrowser 方法以满足您的确切需求。
于 2012-04-17T06:21:42.477 回答
0
为什么不简单地使用 Datatemplate 并让 WPF 完成剩下的工作呢?
使用网络浏览器创建用户控件。您必须添加附加属性,因为您不能直接绑定到源。
<UserControl x:Class="WpfBrowser.BrowserControl" xmlns:WpfBrowser="clr-namespace:WpfBrowser" > <Grid> <WebBrowser WpfBrowser:WebBrowserUtility.BindableSource="{Binding MyPdf}"/> </Grid> </UserControl>
创建一个处理您的uri的视图模型
public class MyPdfVM { public Uri MyPdf { get; set; } public MyPdfVM() { this.MyPdf = new Uri(@"mypdf path"); } }
获取您的 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)); } }
窗口.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>
窗口.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 属性时,网络浏览器都会更新 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,您的浏览器控件将显示新的 pdf。
于 2012-04-17T06:57:54.533 回答