2014-09-24 69 views
1

我想绑定视频预览自定义控件类中的IntPtr VidHandle属性到它的视图模型(vm:DebugHiResCameraWindowViewModel)中的IntPtr PreviewHandle。ViewModel属性没有更新时,它是相应的CustomControl属性更新

在VideoPreview的构造,我呼吁:

this.VidHandle = picBox.Handle; 

更新VideoPreview的VidHandleProperty的DependencyProperty。这工作完美。但是,ViewModel中的PreviewHandle属性未被更新。到时候我打电话:

camera.StartVideoStream(PreviewHandle); 

在视图模型,PreviewHandle是0,因为它从来没有从VideoPreview更新。我有感觉我的DependencyProperty VidHandleProperty没有正确实现,但我可能是错的。

下面是一些代码片段:

主窗口XAML:

<Window 
x:Class="AoiImageLift.Views.DebugHiResCameraWindow" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:vm="clr-namespace:AoiImageLift.Presentation.ViewModels" 
xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms" 
xmlns:com="clr-namespace:AoiImageLift.Components" 
xmlns:local="clr-namespace:AoiImageLift" 
Title="DebugHiResCameraWindow" 
Name="hiResWindow" 
Height="300" 
Width="300"> 
<Window.Resources> 
    <vm:DebugHiResCameraWindowViewModel x:Key="viewModel"/> 
</Window.Resources> 
<Grid> 
    <Grid.RowDefinitions> 
     <RowDefinition/> 
     <RowDefinition/> 
    </Grid.RowDefinitions> 

    <com:VideoPreview 
     DataContext="{StaticResource viewModel}" 
     x:Name="videoHost" 
     VidHandle="{Binding PreviewHandle, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type com:VideoPreview}}}"/> 

    <Button 
     DataContext="{StaticResource viewModel}" 
     Grid.Row="1" 
     Width="100" 
     Height="40" 
     Command="{Binding StartCaptureCommand}" 
     Content="Start"/> 
</Grid> 

VideoPreview类:

public class VideoPreview : WindowsFormsHost 
{ 
    private PictureBox picBox; 
    public static readonly DependencyProperty VidHandleProperty = 
     DependencyProperty.Register(
      "VidHandle", 
      typeof(IntPtr), 
      typeof(VideoPreview), 
      new FrameworkPropertyMetadata 
      { 
       BindsTwoWayByDefault = true 
      }); 

    public VideoPreview() : base() 
    { 
     picBox = new PictureBox(); 
     picBox.Width = (int) this.Width; 
     picBox.Height = (int) this.Height; 

     this.VidHandle = picBox.Handle; 
     this.Child = picBox; 
    } 

    public IntPtr VidHandle 
    { 
     get 
     { 
      return (IntPtr) GetValue(VideoPreview.VidHandleProperty); 
     } 
     set 
     { 
      SetValue(VideoPreview.VidHandleProperty, value); 
     } 
    } 
} 

视图模型类:

public class DebugHiResCameraWindowViewModel : ViewModel 
{ 
    private Uri capturedImage; 
    private BitmapImage bmp; 
    private ISnapImages camera; 

    public DebugHiResCameraWindowViewModel() 
    { 
     camera = LumeneraCamera.Instance; 
     bmp = new BitmapImage(); 
    } 

    public IntPtr PreviewHandle { get; set; } 
    public Uri CapturedImage 
    { 
     get { return capturedImage; } 
     set { capturedImage = value; OnPropertyChanged("CapturedImage"); } 
    } 
    public ICommand StartCaptureCommand 
    { 
     get 
     { 
      return new DelegateCommand(() => 
      { 
       try 
       { 
        camera.StartVideoStream(PreviewHandle); 
       } 
       catch (CustomException ex) 
       { 
        MessageBox.Show(ex.Message, ex.Caption, ex.Button, ex.Image); 
       } 
      }); 
     } 
    } 
} 
+0

该控件的构造函数中的'this.VidHandle = picBox.Handle;'行在绑定前执行'VidHandle =“{Binding PreviewHandle ...''成立。因此绑定将简单地覆盖'VidHandle'的值。你也许可以在'VidHandle'改变回调的属性中设置'picBox.Handle'。 – Clemens 2014-09-24 20:51:19

回答

1

看起来VideoPreview控件的VidHandle控件绑定到您的VideoPreview控件的PreviewHandle(它不存在)。

开始调试时检查输出窗口,它会显示绑定错误(例如,当它找不到属性时)。

也许这是你以后?

<Window 
x:Class="AoiImageLift.Views.DebugHiResCameraWindow" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:vm="clr-namespace:AoiImageLift.Presentation.ViewModels" 
xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms" 
xmlns:com="clr-namespace:AoiImageLift.Components" 
xmlns:local="clr-namespace:AoiImageLift" 
Title="DebugHiResCameraWindow" 
Name="hiResWindow" 
Height="300" 
Width="300"> 
<!-- CHANGED HERE: set DataContext of Window --> 
<Window.DataContext> 
    <vm:DebugHiResCameraWindowViewModel /> 
</Window.DataContext> 
<Grid> 
    <Grid.RowDefinitions> 
     <RowDefinition/> 
     <RowDefinition/> 
    </Grid.RowDefinitions> 

    <!-- CHANGED HERE: removed DataContext (set at Window) -- updated binding --> 
    <com:VideoPreview 
     x:Name="videoHost" 
     VidHandle="{Binding PreviewHandle}"/> 

    <!-- CHANGED HERE: removed DataContext (set at Window) -- binding OK --> 
    <Button 
     Grid.Row="1" 
     Width="100" 
     Height="40" 
     Command="{Binding StartCaptureCommand}" 
     Content="Start"/> 
</Grid> 

DataContext的是继承,你可以在窗口中设置它,它会由子控件是已知的。

回复:评论......虚拟机通常会优先 - 如果您在所有获取/设置者上设置断点,您可以看到该命令...... 0来自DP的默认值(可以是因为DP是静态的,所以它不能是PictureBox)。不知道这是适当的,但它的工作原理:

在你VideoPreview构造函数中添加:

base.Loaded += VideoPreview_Loaded; 

,并添加

void VideoPreview_Loaded(object sender, RoutedEventArgs e) 
{ 
    this.VidHandle = picBox.Handle; 
} 

在视图中,更新绑定:

VidHandle="{Binding PreviewHandle, UpdateSourceTrigger=PropertyChanged}" 

您可能还想要Mode=OneWayToSource,假设手柄只能回来m VideoPreview

+0

感谢您的回应,但是当我做出这些更改时,DebugHiResCameraWindowViewModel的PreviewHandle属性仍然为0,当我单击按钮时,它告诉我VideoPreview类中的VidHandle的值不是对视图模型中的绑定属性。我的VideoPreview自定义控件类是否正确实现?我不需要更新视图模型? – kformeck 2014-09-24 20:02:33

+0

在答案底部看到更新 – bdimag 2014-09-24 20:50:45

+1

您的更改完美无缺!关键是在OnLoaded事件处理程序中设置VideoPreview类的VidHandle,而不是在构造函数中。 – kformeck 2014-09-25 14:37:41