在WPF中引用Button位置设置Window Top + Left

问题描述 投票:-1回答:1

前言

StackOverflow上有很多关于这个主题的类似问题,我浏览了很多而没有找到合适的答案,这将适用于我的问题。

任务

我有一个MVVM模式的WPF窗口,它有很多按钮打开其他窗口。我希望我的大多数窗口都与我的按钮相关(我的MainWindow右上角有一个工具栏,希望大多数小窗口出现在我的按钮下方),或者至少在同一个窗口下方屏幕为我的MainWindow。

问题

起初,我认为这不是一个大问题,谷歌有很多关于这个主题的博客和问题,但所有这些都不适用于我的项目。

我正在使用MVVM模式,这意味着:

  • 我不能在我的按钮上使用Mouse.GetPosition(ButtonName),因为ViewModel不知道他们的名字
  • 我不能在Click-Event中使用Mouse.GetPosition(sender),因为大多数Buttons都使用控件。
  • 我显然也不能在我的视图后面的代码中使用PointToScreen,因为它会导致异常(此可视对象未连接到“PresentationSource”)
  • 我可以在我视图的代码后面的MouseMove-Event上使用Mouse.GetPosition(this)并将其交给我的ViewModel,它将更新一个Property,我可以在创建窗口时在我的命令中使用它,但我不喜欢有这个想法永久更新房产。也没有PointToScreen我无法设置与我的屏幕相关的点。
  • 我不能使用任何WinForms引用,因为这会导致我当前项目中的冲突

  • 除了按钮,我还在我的MainWindow中托管了一个带有超链接的UserControl,它打开了额外的窗口,应该与超链接有关。

研究

  • 问题here有不同的答案,但没有一个对我有用。
  • 由于我的ViewModel不知道XAML元素,我不能简单地通过点符号访问here
  • 我的ViewModel不知道WorkingArea,所以我甚至无法让我的窗口显示在与我的MainWindow相同的屏幕上,如here所示
  • 正如大多数其他答案一样,this one似乎无法在ViewModel中运行

我花了很长时间在一个问题上,起初看起来似乎微不足道。由于我目前看到的大多数问题似乎都是针对没有MVVM的窗口,因此在ViewModel中将窗口的位置设置为鼠标坐标或点击按钮坐标的正确方法是什么?

编辑:注释中的请求MouseDownEvent:Xaml:

<Window x:Class="MySampleProject.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:MySampleProject"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525"
        MouseDown="Window_MouseDown">

C#:

private void Window_MouseDown(object sender, MouseEventArgs e)
{
    if (m_oDataContext != null)
    {
        m_oDataContext.MouseTest(Mouse.GetPosition(this));
    }
}

oDataContext是我的ViewModel。我的MouseTest()目前是空的。我确实在第一个括号设置了一个断点。只有在我的窗口中左键单击时才会到达断点,而不是在其中一个托管控件中。

c# wpf xaml mvvm
1个回答
0
投票

下面是一个如何在Vm中将参数传递给Command的示例:

窗口类:

public partial class MainWindow
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext= new MyVm();
    }

    private void BtnWin1_OnClick(object sender, RoutedEventArgs e)
    {
        var dataContext = DataContext as MyVm;
        var relativePoint = ((Button)sender).TransformToAncestor(this).Transform(new Point(0, 0));
        relativePoint.X += this.Left;
        relativePoint.Y += this.Top;
        dataContext?.OpenWindow1Command.Execute(relativePoint);
    }

    private void BtnWin2_OnClick(object sender, RoutedEventArgs e)
    {
        var dataContext = DataContext as MyVm;
        var relativePoint = ((Button)sender).TransformToAncestor(this).Transform(new Point(0, 0));
        relativePoint.X += this.Left;
        relativePoint.Y += this.Top;
        dataContext?.OpenWindow2Command.Execute(relativePoint);
    }
}

VM类:

public class MyVm : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public ICommand OpenWindow1Command { get; }
    public ICommand OpenWindow2Command { get; }

    public MyVm()
    {
        OpenWindow1Command = new RelayCommand(OpenWindow1Command_Execute);
        OpenWindow2Command = new RelayCommand(OpenWindow2Command_Execute);
    }

    void OpenWindow1Command_Execute(object parameter)
    {
        var point = (Point)parameter;

        var win1 = new Window1{WindowStartupLocation = WindowStartupLocation.Manual, Left = point.X, Top = point.Y};
        win1.Show();
    }

    void OpenWindow2Command_Execute(object parameter)
    {
        var point = (Point)parameter;

        var win2 = new Window2 { WindowStartupLocation = WindowStartupLocation.Manual, Left = point.X, Top = point.Y };
        win2.Show();
    }
} 

和Relay类,如果你还没有实现:

 public class RelayCommand : ICommand
{
    private readonly Action<object> _execute;
    private readonly Func<bool> _canExecute;

    public RelayCommand(Action<object> execute, Func<bool> canExecute = null)
    {
        _execute = execute ?? throw new ArgumentNullException(nameof(execute));
        _canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        return _canExecute == null || _canExecute.Invoke();
    }

    public event EventHandler CanExecuteChanged
    {
        add => CommandManager.RequerySuggested += value;
        remove => CommandManager.RequerySuggested -= value;
    }

    public void Execute(object parameter)
    {
        _execute(parameter);
    }
}

您将使用此方法松开Command的CanExecute功能,但将完成工作。

© www.soinside.com 2019 - 2024. All rights reserved.