我试图将VideoPreview定制控件类中的IntPtr VidHandle属性绑定(bind)到其 View 模型(vm:DebugHiResCameraWindowViewModel)中的IntPtr PreviewHandle。

在VideoPreview的构造函数中,我调用:

this.VidHandle = picBox.Handle;

更新VideoPreview的VidHandleProperty DependencyProperty。这很完美。但是,未更新ViewModel中的PreviewHandle属性。到我打电话时:
camera.StartVideoStream(PreviewHandle);

在 View 模型中,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);
                }
            });
        }
    }
}

最佳答案

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

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

也许这就是你所追求的?

<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是继承的,您可以在Window上设置它,子控件将知道它。

回复:注释... VM通常会优先处理-如果在所有getter/setter上设置断点,则可以看到顺序... 0来自DP的默认值(可以在meta中设置) ,但不能是PictureBox,因为DP是静态的)。不知道这是否合适,但是它可以工作:

在您的VideoPreview构造函数中,添加:
base.Loaded += VideoPreview_Loaded;

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

在 View 中,更新绑定(bind):
VidHandle="{Binding PreviewHandle, UpdateSourceTrigger=PropertyChanged}"

您可能还需要Mode=OneWayToSource,假设句柄应仅来自VideoPreview

关于c# - 相应的CustomControl属性更新时,ViewModel属性未更新,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/26024197/

10-15 16:39