この SO questionで説明されているものと同様の問題が発生しています。推奨される解決策は、提示したいページ (PDF) ごとに新しい WebBrowser コントロールを作成することです (古い WebBrowser コントロールを上書きします)。MVVM でそのような新しいコントロールを作成する正しい方法は何ですか? ビューの実装について VM を認識させないようにしています。
3 に答える
VM が知る必要があるのはなぜですか? ビューを適切なイベントにフックして (必要に応じてイベントを定義するか、単に を使用してPropertyChanged
)、コントロールを再作成できないのはなぜですか?
- CreateBrowser() というメソッドを使用して、IBrowserCreator という名前の ViewModel にインターフェイスを作成します。
- ViewHelper という名前の ViewModel に静的クラスを作成し、それに BrowserCreator という名前の IBrowserCreator タイプの静的プロパティを追加します。
- View レイヤーで、ViewModel.IBrowserCreator を実装する BrowserCreator という新しいクラスを作成します。
- ビューの初期化コードで、BrowserCreator をインスタンス化し、それを ViewModel.ViewHelper.BrowserCreator に割り当てます。
ViewModel から、次を呼び出すことができるはずです。
ViewHelper.BrowserCreator.CreateBrowser()
明らかに、この回答はフレームワークにすぎませんが、一般的なアイデアが得られるはずです。正確なニーズに合わせて CreateBrowser メソッドを実装する必要があります。
単純に Datatemplate を使用して、残りを WPF に任せてみませんか?
Webブラウザでユーザーコントロールを作成します。ソースに直接バインドできないため、添付プロパティを追加する必要があります。
<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 を追加して、ビューで contentcontrol を取得します
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)); } }
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 プロパティを変更するたびに、Web ブラウザが 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を表示することがわかるように、いくつかのコードを追加しました。