Перемещение контролов по ItemsControl с использованием MVVM [дубликат]

149
04 ноября 2021, 12:00
На этот вопрос уже даны ответы здесь:
Drag&Drop по правилам WPF (2 ответа)
Закрыт 1 год назад.

Мой UserControl:

public class ElementViewModel : ViewModelBase
{
    public ElementViewModel() { }
    public double X { get; set; }
    public double Y { get; set; }

    public Command<ElementViewModel> OnMouseDown => new Command<ElementViewModel>((elem) =>
    {
        // ???
    });
    public Command<ElementViewModel> OnMouseMove => new Command<ElementViewModel>((elem) =>
    {
        // ???
    });
    public Command<ElementViewModel> OnMouseUp => new Command<ElementViewModel>((elem) =>
    {
        // ???
    });
    protected override async Task InitializeAsync() 
        => await base.InitializeAsync();
    protected override async Task CloseAsync() => 
        await base.CloseAsync();
}

MainWindow View:

<ItemsControl ItemsSource="{Binding Elements}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas  IsItemsHost="True"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemContainerStyle>
        <Style TargetType="ContentPresenter">
            <Setter Property="Canvas.Left" Value="{Binding X}"/>
            <Setter Property="Canvas.Top"  Value="{Binding Y}"/>
        </Style>
    </ItemsControl.ItemContainerStyle>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <views:Element>
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="MouseDown">
                        <i:InvokeCommandAction Command="{Binding OnMouseDown}" 
                                                   CommandParameter="{Binding}"/>
                    </i:EventTrigger>
                    <i:EventTrigger EventName="MouseMove">
                        <i:InvokeCommandAction Command="{Binding OnMouseMove}"
                                                   CommandParameter="{Binding}"/>
                    </i:EventTrigger>
                    <i:EventTrigger EventName="MouseUp">
                        <i:InvokeCommandAction Command="{Binding OnMouseUp}"
                                                   CommandParameter="{Binding}"/>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </views:Element>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

И MainWindow ViewModel:

public class MainWindowViewModel : ViewModelBase
{
    public MainWindowViewModel()
    {
        Elements.Add(new ElementViewModel());
        Elements.Add(new ElementViewModel());
    }
    public ObservableCollection<ElementViewModel> Elements { get; set; }
        = new ObservableCollection<ElementViewModel>();

    protected override async Task InitializeAsync() 
        => await base.InitializeAsync();
    protected override async Task CloseAsync() 
        => await base.CloseAsync();
}

Хочу реализовать перетягивание мышкой свой ElementViewMode по ItemsControl. Как это сделать без парамеротров из EventArgs? Или как получить эти параметры в Command? Перепробывал много вариантов из инета, все либо без MVVM либо не работают(может плохо искал, тогда дайте ссылку). Пользуюсь Catel. Решения без Catel тоже должно подойти, главное чтоб MVVM соблюдался.

P.S. Пользуюсь ещо и Fody так что все свойства на самом деле PropertyChanged

Answer 1

Если вариант с получением EventArgs во ViewModel приемлемый, то в Catel можно использовать EventToCommand

<Commands:EventToCommand Command="{Binding Edit}" DisableAssociatedObjectOnCannotExecute="False" PassEventArgsToCommand="True" />
Answer 2

Можно попробовать (да, конечно, это только кателовское решение) привесить этот behavior: https://docs.catelproject.com/5.0/reference/catel.mvvm/catel/windows/interactivity/dragdrop на ItemControl и слушать событие ObservableCollection.CollectionChanged во VM...все в рамках MVVM

P.S. я не очень уверен тоже, что использовать Command Binding на MouseMove хорошая идея... но, например, чтобы не "загрязнять" VM аргументами событий из EventToCommand (https://catelproject.atlassian.net/wiki/spaces/CTL/pages/1409072/EventToCommand) можно использовать конвертер:

<catel:EventToCommand Command="{Binding MyCommand}" 
PassEventArgsToCommand="True" DisableAssociatedObjectOnCannotExecute="False"
EventArgsConverter="{StaticResource SomeArgsConverter}"/>
READ ALSO
Openweathermap не работает без VPN

Openweathermap не работает без VPN

Нужно создать приложение погды на C#В теории все просто, но на практике все туторы на С# котороые я находил используют openweathermap, а у меня на этом...

162
Тормозит dataGridView

Тормозит dataGridView

Поместил dataGridView в wiforms и создал таблицу 5 колонок / 1000 строк Первую колонку полностью заполнил данными string - строки из 10-15 символов, а остальные...

227
Selenium не видит элемент

Selenium не видит элемент

Что не так в Selenium или xpath ? Я использую xpath //span[@id='responseDate'], а проверка на наличие элемента приносит мне false, хотя в тоже время - я без проблем могу...

189
PHP isset() $_POST не работает

PHP isset() $_POST не работает

Постоянно выводит false

196