Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Wpf MVVM Light EventToCommand不使用CaptureMouse_Wpf_Mvvm Light - Fatal编程技术网

Wpf MVVM Light EventToCommand不使用CaptureMouse

Wpf MVVM Light EventToCommand不使用CaptureMouse,wpf,mvvm-light,Wpf,Mvvm Light,我在EventToCommand中遇到了一些问题,它的行为与我对CaptureMouse的预期不符 我有一个ResizeGrip,我已经在上面定义了几个EventToCommand: <ResizeGrip Name="ResizeGrip" HorizontalAlignment="Right" VerticalAlignment="Bottom" Cursor="SizeNWSE"> <i:Interaction.Triggers> <i:EventTrig

我在EventToCommand中遇到了一些问题,它的行为与我对CaptureMouse的预期不符

我有一个ResizeGrip,我已经在上面定义了几个EventToCommand:

<ResizeGrip Name="ResizeGrip" HorizontalAlignment="Right" VerticalAlignment="Bottom" Cursor="SizeNWSE">
<i:Interaction.Triggers>
  <i:EventTrigger EventName="MouseLeftButtonDown">
   <cmd:EventToCommand Command="{Binding ResizeStartCommand}" PassEventArgsToCommand="True" />
  </i:EventTrigger>
  <i:EventTrigger EventName="MouseLeftButtonUp">
   <cmd:EventToCommand Command="{Binding ResizeStopCommand}" PassEventArgsToCommand="True" />
  </i:EventTrigger>
  <i:EventTrigger EventName="MouseMove">
   <cmd:EventToCommand Command="{Binding ResizeCommand}" PassEventArgsToCommand="True" />
  </i:EventTrigger>
 </i:Interaction.Triggers>
 </ResizeGrip>
OnRequestResizeStart和OnRequestResizeStop命令工作正常,OnRequestResize工作正常。。。但只有当我真的超过了尺寸控制时。CaptureMouse似乎并没有实际将所有鼠标事件发送到ResizeGrip

这是EventToCommand的一个限制,还是需要发生一些特殊的事情


谢谢你的帮助

为什么要为此使用命令而不是标准事件处理程序?这显然是属于代码隐藏的UI逻辑,而不是ViewModel

****更新**

如果您在ControlTemplate中使用它,您可以将控件的代码视为您的代码隐藏。要连接事件,可以使用TemplatePart模式并连接到OnApplyTemplate中的特殊命名元素。为了方便提供大小(或VM需要的任何其他内容),您可以添加一个DP来存储适当的值,并将VM属性绑定到该值。如果需要从VM设置初始大小之类的操作,这也允许进行双向绑定

// this doesn't enforce the name but suggests it
[TemplatePart(Name = "PART_Resizer", Type = typeof(ResizeGrip))]
public class MyContainer : ContentControl
{
    private ResizeGrip _grip;

    public static readonly DependencyProperty ContainerDimensionsProperty = DependencyProperty.Register(
        "ContainerDimensions",
        typeof(Size),
        typeof(MyContainer),
        new UIPropertyMetadata(Size.Empty, OnContainerDimensionsChanged));

    private static void OnContainerDimensionsChanged(DependencyObject dObj, DependencyPropertyChangedEventArgs e)
    {
        MyContainer myContainer = dObj as MyContainer;
        if (myContainer != null)
        {
            Size newValue = (Size)e.NewValue;
            if (newValue != Size.Empty)
            {
                myContainer.Width = newValue.Width;
                myContainer.Height = newValue.Height;
            }
        }
    }

    public Size ContainerDimensions
    {
        get { return (Size)GetValue(ContainerDimensionsProperty); }
        set { SetValue(ContainerDimensionsProperty, value); }
    }

    static MyContainer()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(MyContainer), new FrameworkPropertyMetadata(typeof(MyContainer)));
    }

    public override void OnApplyTemplate()
    {
        _grip = Template.FindName("PART_Resizer", this) as ResizeGrip;
        if (_grip != null)
        {
            _grip.MouseLeftButtonDown += Grip_MouseLeftButtonDown;
            // other handlers
        }

        SizeChanged += MyContainer_SizeChanged;
        base.OnApplyTemplate();
    }

    void MyContainer_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        // update your DP
    }
    ...
}
要使用它,您需要确保模板中的元素具有与属性匹配的正确类型和名称

<local:MyContainer ContainerDimensions="{Binding Path=SavedSize}">
    <local:MyContainer.Template>
        <ControlTemplate TargetType="{x:Type local:MyContainer}">
            <Grid>
                <Border Background="{TemplateBinding Background}">
                    <ContentPresenter/>
                </Border>
                <ResizeGrip x:Name="PART_Resizer" HorizontalAlignment="Right" VerticalAlignment="Bottom"
                            Width="20" Height="20"/>
            </Grid>
        </ControlTemplate>
    </local:MyContainer.Template>
</local:MyContainer>

您现在可以将此模板放在任何位置,因为它没有声明任何事件处理程序,因此独立于代码隐藏文件。现在,您已经将所有UI逻辑封装在特定于UI的类中,但仍然可以通过绑定来访问VM中所需的数据


如果您仔细想想,这是您通常与内置控件交互的方式。如果您使用扩展器,您不希望将ToggleButton的单击传递到VM中,并尝试使控件从此处展开,但您可能想知道扩展器是打开的还是关闭的,因此有一个IsExpanded属性,您可以绑定并保存并加载为数据。

我在使用事件与命令时没有问题,因为我还在学习用WPF和MVVM模式组织代码的最佳方法。但是我仍然需要ViewModel来知道发生了什么,这样我就可以更新正在调整大小的对象模型。让代码隐藏与底层模型交互的最佳方式是什么?另一个有趣的问题是——ResizeGrip是在ResourceDictionary中的样式(当前)中定义的。在这种情况下,我在定义事件时遇到了很多问题。谢谢你的指点,John。我能够按照您的建议进行一切设置,并且基于我之前编写的代码,所有绑定仍然有效。不需要依赖财产。。。至少现在是这样。也让我大吃一惊!不幸的是,这并没有解决我遇到的问题,因为ResizeGrip仍然会在指针“掉”下来时丢失鼠标捕获(在速度较慢的计算机上)。但这有助于缩小潜在的原因!
// this doesn't enforce the name but suggests it
[TemplatePart(Name = "PART_Resizer", Type = typeof(ResizeGrip))]
public class MyContainer : ContentControl
{
    private ResizeGrip _grip;

    public static readonly DependencyProperty ContainerDimensionsProperty = DependencyProperty.Register(
        "ContainerDimensions",
        typeof(Size),
        typeof(MyContainer),
        new UIPropertyMetadata(Size.Empty, OnContainerDimensionsChanged));

    private static void OnContainerDimensionsChanged(DependencyObject dObj, DependencyPropertyChangedEventArgs e)
    {
        MyContainer myContainer = dObj as MyContainer;
        if (myContainer != null)
        {
            Size newValue = (Size)e.NewValue;
            if (newValue != Size.Empty)
            {
                myContainer.Width = newValue.Width;
                myContainer.Height = newValue.Height;
            }
        }
    }

    public Size ContainerDimensions
    {
        get { return (Size)GetValue(ContainerDimensionsProperty); }
        set { SetValue(ContainerDimensionsProperty, value); }
    }

    static MyContainer()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(MyContainer), new FrameworkPropertyMetadata(typeof(MyContainer)));
    }

    public override void OnApplyTemplate()
    {
        _grip = Template.FindName("PART_Resizer", this) as ResizeGrip;
        if (_grip != null)
        {
            _grip.MouseLeftButtonDown += Grip_MouseLeftButtonDown;
            // other handlers
        }

        SizeChanged += MyContainer_SizeChanged;
        base.OnApplyTemplate();
    }

    void MyContainer_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        // update your DP
    }
    ...
}
<local:MyContainer ContainerDimensions="{Binding Path=SavedSize}">
    <local:MyContainer.Template>
        <ControlTemplate TargetType="{x:Type local:MyContainer}">
            <Grid>
                <Border Background="{TemplateBinding Background}">
                    <ContentPresenter/>
                </Border>
                <ResizeGrip x:Name="PART_Resizer" HorizontalAlignment="Right" VerticalAlignment="Bottom"
                            Width="20" Height="20"/>
            </Grid>
        </ControlTemplate>
    </local:MyContainer.Template>
</local:MyContainer>