代码之家  ›  专栏  ›  技术社区  ›  Nicholas Pappas

MVVM Light EventToCommand不使用CaptureMouse

  •  0
  • Nicholas Pappas  · 技术社区  · 14 年前

    我在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>
    

    ResizeStartCommand = new RelayCommand<MouseButtonEventArgs>(
        (e) => OnRequestResizeStart(e));
    ResizeStopCommand = new RelayCommand<MouseButtonEventArgs>(
        (e) => OnRequestResizeStop(e));
    ResizeCommand = new RelayCommand<MouseEventArgs>(
        (e) => OnRequestResize(e),
        param => CanResize);
    

    最后,我用我所有的逻辑来调整大小:

    void OnRequestResizeStart(MouseButtonEventArgs e)
    {
        bool r = Mouse.Capture((UIElement)e.Source);
        Console.WriteLine("mouse down: " + r.ToString());
    }
    void OnRequestResizeStop(MouseButtonEventArgs e)
    {
        ((UIElement)e.Source).ReleaseMouseCapture();
        _canResize = false;
    }
    void OnRequestResize(MouseEventArgs e)
    {
        Console.WriteLine("mouse move");
    }
    bool CanResize
    { get { return _canResize; } }
    

    OnRequestResizeStart&OnRequestResizeStop命令工作正常,OnRequestResize工作正常。。。但只有当我真的在调整尺寸的时候。CaptureMouse似乎并没有实际将所有鼠标事件发送到ResizeGrip。

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

    1 回复  |  直到 14 年前
        1
  •  0
  •   John Bowen    14 年前

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

    ****更新**

    // 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属性,您可以将其绑定并保存并作为数据加载。