MVVM光EventToCommand不工作与CaptureMouse
-
25-09-2019 - |
题
我有一些麻烦的EventToCommand不表现为我期望与CaptureMouse。
我有已经定义几个EventToCommand对一个ResizeGrip:
<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工作......但只有当我真正是在ResizeGrip。它不会出现该CaptureMouse实际上不发送所有的鼠标事件到ResizeGrip。
这是EventToCommand的限制,或确实发生一些特别的需求?
感谢您的帮助!
解决方案
为什么要使用命令为这个而不是标准的事件处理程序?这清楚地是,在代码隐藏属于UI逻辑,而不是一个视图模型。
****更新**
在,你在ControlTemplate中使用此,你可以把控件的为您的后台代码的情况。要做到这些事件的连接,你可以使用TemplatePart模式,连接到OnApplyTemplate特别命名的元素。为了便于将尺寸(或任何其他的虚拟机需要),你可以添加一个DP存储适当的值,并绑定一个虚拟机属性这一点。这也使得做了两路,如果你需要做类似的东西从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逻辑的,但你能在你的虚拟机通过结合它仍然需要访问数据。
如果你想想看,这是你的方式通常与内置控件进行交互。如果您使用的扩展,你不想切换按钮的点击进入你的虚拟机,并尽量使控制从那里展开,但你可能想知道的扩展是开放的还是封闭的,所以有一个IsExpanded属性,您可以结合和保存和负载数据。