How should I move a WPF Window using MVVM?

徘徊边缘 提交于 2020-08-24 21:53:52

问题


This is probably overkill on the MVVM pattern but it's new to me and I'm interested to see if it is possible.

If I attach to the MouseMove event for a Window and do DragMove, I can move a bordeless window. Can I achieve this by some other method in MVVM or should I just accept adding this code to the Window's codebehind?


回答1:


This is pure UI logic and doesn't belong in a ViewModel. The only reason you wouldn't want to put this in your code-behind would be for re-use and that is better solved with a custom Window derived control.




回答2:


Personally I think any solution using MVVM would not make this code any better. Also, this is typically something that's view related and hasn't got anything to do with the data you're displaying.




回答3:


IMHO, unless this is something that effects your data (aka the Model) then it is View code and should be in the View's code-behind and not in the Model.




回答4:


I'm going to actually answer your question. The answer is yes. I'm using Cinch to assist me in the event binding and view model creation. The solution uses DragMove, but not as part of the code-behind (which is what I believe you are asking).

Event binding in the XAML:

<Window 
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:cinchV2="clr-namespace:Cinch;assembly=Cinch.WPF"
    ...>
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="MouseLeftButtonDown">
            <cinchV2:EventToCommandTrigger Command="{Binding MouseLeftButtonDown}" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
    <Grid>
        ...
    </Grid>
</Window>

In the ViewModel:

[ExportViewModel("MainViewModel")]
[PartCreationPolicy(CreationPolicy.NonShared)]
internal sealed class MainViewModel : ViewModelBase
{
    public SimpleCommand<object, EventToCommandArgs> MouseLeftButtonDown { get; private set; }

    [ImportingConstructor]
    public MainViewModel(IUIVisualizerService uiVisualizerService)
    {
        ...
        MouseLeftButtonDown = new SimpleCommand<object, EventToCommandArgs>(OnMouseLeftButtonDown);
    }

    private static void OnMouseLeftButtonDown(EventToCommandArgs e)
    {
        ((Window)e.Sender).DragMove();
    }
}

Fairly simple, right? Any events that come from the UI contain the View as the sender. So, here, we simply call the method on the view within the event handler in the ViewModel.

The project I'm working on uses no code-behind (even if it is not recommended in MVVM).




回答5:


I know that I am a little late to the question, but this is what I have been using for sometime now and it works like a charm.

DashboardViewModel viewModel;
public DashboardView()
{
    InitializeComponent();
    viewModel = new DashboardViewModel();
    viewModel.RequestClose += (s, e) => Application.Current.Dispatcher.Invoke(this.Close);
    viewModel.RequestMinimize += (s, e) => Application.Current.Dispatcher.Invoke(() => { this.WindowState = WindowState.Minimized; });
    DataContext = viewModel;
}

and something like this in your viewModel

#region Public Event Handlers
public event EventHandler<EventArgs> RequestClose;
public event EventHandler<EventArgs> RequestMinimize;
#endregion

Using the ICommand interface...

#region ICommand Members
public ICommand CloseCommand { get; private set; }
public ICommand MinimizeCommand { get; private set; }
#endregion

Configure the commands...

private void SetupCommands()
{
    CloseCommand = new RelayCommand(CloseApplication);
    MinimizeCommand = new RelayCommand(MinimizeApplication);
}

Here is the RelayCommand class.

public class RelayCommand : ICommand
{
#region Private Readonly Properties
private readonly Action<object> executeCommand;
private readonly Predicate<object> canExecute;
#endregion

#region Constructors
public RelayCommand(Action<object> execute) : this(execute, null)
{

}
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
    if (execute == null) 
        throw new ArgumentNullException("execute");
    this.executeCommand = execute; 
    this.canExecute = canExecute;
}
#endregion

#region Public ICommand Members
public bool CanExecute(object parameter)
{
    return canExecute == null ? true : canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
    add { CommandManager.RequerySuggested += value; }
    remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
    executeCommand(parameter);
}
#endregion
}

And some example methods...

private void MinimizeApplication(object obj)
{
    RequestMinimize(this, new EventArgs());
}
private void CloseApplication(object obj)
{
    RequestClose(this, new EventArgs());
}

Hope this helps!




回答6:


I know it's an old question. However I prepared another simple implementation. Use following behavior to make window moveable:

public class WindowMoveBehavior : Behavior<Grid>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.MouseLeftButtonDown += AssociatedObject_MouseLeftButtonDown;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.MouseLeftButtonDown -= AssociatedObject_MouseLeftButtonDown;
        base.OnDetaching();
    }

    private void AssociatedObject_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        Window.GetWindow(AssociatedObject).DragMove();
    }
}

Xaml example:

<Style x:Key="CustomWindowStyle" TargetType="{x:Type Window}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Window}">
                <Grid>
                    <i:Interaction.Behaviors>
                        <behaviors:WindowMoveBehavior/>
                    </i:Interaction.Behaviors>
     <!-- different controls and content -->
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>


来源:https://stackoverflow.com/questions/3425500/how-should-i-move-a-wpf-window-using-mvvm

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!