MVVM Light EventToCommand не работает с Capturemouse
-
25-09-2019 - |
Вопрос
У меня есть некоторые проблемы с EventToCommand, не ведем себя так, как я ожидаю, что с Capturemouse.
У меня есть резервуар, который я определил несколько 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 работают нормально, и онrequestresize работает ... Но только когда я на самом деле через резюме. Это не отображается, что Capturemouse на самом деле не отправляет все события мыши к резюме.
Это ограничение EventToCommand или что-то особое надо происходить?
Спасибо за любую помощь!
Решение
Почему вы используете команды для этого вместо стандартных обработчиков событий? Это явно логика пользовательского интерфейса, которая принадлежит коду-позади, а не просмотрамодель.
****ОБНОВИТЬ**
В случае, если вы используете это в контрольной таблице, вы можете лечить код управления в качестве кода. Для выполнения соединений событий вы можете использовать шаблон шаблона и подключаться к специальному именованному элементу в 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, но все еще может получить доступ к данным в вашу виртуальную машину, привязывая его.
Если вы думаете об этом, это так, как вы обычно взаимодействуете со встроенным элементом управления. Если вы используете расширитель, вы не захотите пройти клики ToggleButton в вашу виртуальную машину и попробуйте сделать элемент управления оттуда, но вы можете узнать, открыт ли расшифер или закрыт, так что есть свойство ISExpanded может привязать и сохранить и загружать в качестве данных.