问题
I'm developing a WPF-application with MVVM. In this application I need to have an OpenGL-Control (I'm using OpenTK). The currently only useful way to get OpenGL in WPF is using a WindowsFormsHost. Until here, there's no problem.
To add content to my Scene I need access to the OpenGL-Control in my View. Of course I want to add and edit the content in the ViewModel. So, how can I get access to the OpenGL-Control without violating the MVVM-Pattern?
I'm using a scene-object which can get initialized in the View and then needs to be transferred somehow to the ViewModel. I tried this using the Tag-property of the WindowsFormsHost but without success (compare below). The property in the ViewModel is not getting updated.
Any ideas?
XAML
<UserControl x:Class="FancyOpenGlControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<WindowsFormsHost x:Name="WindowsFormsHost" Tag="{Binding Scene, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</UserControl>
C#
public FancyOpenGlControl()
{
this.InitializeComponent();
this.glControl = new OpenGLControl();
this.glControl.Dock = DockStyle.Fill;
this.WindowsFormsHost.Child = this.glControl;
this.glControl.HandleCreated += this.GlControlOnHandleCreated;
}
private void GlControlOnHandleCreated(object sender, EventArgs eventArgs)
{
this.WindowsFormsHost.Tag = new Scene(this.glControl);
// Doesn't work.
//BindingExpression bindingExpression = this.WindowsFormsHost.GetBindingExpression(TagProperty);
//if (bindingExpression != null)
//{
// bindingExpression.UpdateSource();
//}
}
回答1:
There are two options I can think of.
1) Set your viewmodel property directly from the view code behind. You will need to do this in response to the view's DataContextChanged
event, since your ViewModel won't be hooked up yet in the view's constructor. This will also mean casting the DataContext
to a known type of ViewModel. I don't really have a problem with that but some do.
private void FancyOpenGlControl_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
var vm = this.DataContext as MyViewModel;
if (vm != null)
vm.GlControl = this.glControl;
}
2) If you prefer slightly looser coupling, then you can create a dependency property on your view and just assign your glControl to that when you create it. You can then bind the property to any ViewModel property you want just like normal. eg:
Code behind:
public static readonly new DependencyProperty GControlProperty =
DependencyProperty.Register("GLControl", typeof(OpenGLControl), typeof(FancyOpenGlControl), new PropertyMetadata(null));
public OpenGLControl GLControl
{
get { return (OpenGLControl )GetValue(DocumentProperty); }
set { SetValue(GLControlProperty , value); }
}
public FancyOpenGlControl()
{
this.InitializeComponent();
this.GLControl= new OpenGLControl();
this.GLControl.Dock = DockStyle.Fill;
this.WindowsFormsHost.Child = this.GLControl;
}
XAML:
<UserControl x:Class="FancyOpenGlControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
GLControl="{Binding VMControlProperty}">
<WindowsFormsHost x:Name="WindowsFormsHost"/>
来源:https://stackoverflow.com/questions/23733822/wpf-mvvm-winformshost-with-opengl-control