简体   繁体   中英

ViewModel property not updating when it's corresponding CustomControl property is updated

I am trying to bind the IntPtr VidHandle property in the VideoPreview custom control class to the IntPtr PreviewHandle in it's view model (vm:DebugHiResCameraWindowViewModel).

In the constructor of VideoPreview, I call:

this.VidHandle = picBox.Handle;

to update the VideoPreview's VidHandleProperty DependencyProperty. This works perfectly. However, the PreviewHandle property in the ViewModel is not being updated. By the time I call:

camera.StartVideoStream(PreviewHandle);

in the view model, PreviewHandle is 0 because it was never updated from VideoPreview. I have the feeling my DependencyProperty VidHandleProperty is not implemented correctly but I could be wrong.

Here are some code snippets:

Main Window 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 class:

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);
        }
    }
}

View Model class:

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);
                }
            });
        }
    }
}

It looks like VidHandle of the VideoPreview control is bound to PreviewHandle of your VideoPreview control (which does not exist).

Check the output window when you start debugging, it should show you the binding errors (eg when it can't find a property).

Maybe this is what you're after?

<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 is inherited, you can set it at the Window and it will be known by the child controls.

Re: the comment... The VM would usually take precedence -- you can see the order if you set breakpoints on all the getters/setters... The 0 is coming from the DP's default value (this can be set in the meta, but it can't be of the PictureBox since the DP is static). Not sure if this is appropriate, but it works:

In your VideoPreview constructor, add:

base.Loaded += VideoPreview_Loaded;

and also add

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

In the view, update the binding:

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

You may also want Mode=OneWayToSource , assuming the handle should only come from the VideoPreview

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM