Skip to content

Instantly share code, notes, and snippets.

@Jadd
Created April 24, 2017 06:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Jadd/e5754f1a024b5e68b6761c137477d432 to your computer and use it in GitHub Desktop.
Save Jadd/e5754f1a024b5e68b6761c137477d432 to your computer and use it in GitHub Desktop.
WPF/MVVM drag-and-drop process selector.
<UserControl x:Class="Ace.UI.Windows.Controls.ProcessSelector"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:viewModels="clr-namespace:Ace.UI.Windows.ViewModels"
mc:Ignorable="d">
<UserControl.DataContext>
<viewModels:ProcessSelectorViewModel />
</UserControl.DataContext>
<StackPanel>
<Grid Margin="0 0 0 8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid x:Name="Target" Grid.Column="0" Background="Transparent" MouseDown="Target_MouseDown" MouseUp="Target_MouseUp">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseUp">
<i:InvokeCommandAction Command="{Binding SelectCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<materialDesign:PackIcon Kind="Target" Width="36" Height="36" Foreground="{DynamicResource PrimaryHueDarkBrush}" />
</Grid>
<Grid Grid.Column="1" Margin="8 0 0 0" VerticalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0" VerticalAlignment="Center" Text="Process ID:" />
<TextBlock Grid.Column="1" Grid.Row="0" VerticalAlignment="Center" Text="{Binding Path=SelectedProcess.Id}" />
<TextBlock Grid.Column="0" Grid.Row="1" VerticalAlignment="Center" Text="Process Name:" />
<TextBlock Grid.Column="1" Grid.Row="1" VerticalAlignment="Center" Text="{Binding Path=SelectedProcess.ProcessName, StringFormat={}{0}.exe}" />
</Grid>
</Grid>
<TextBlock HorizontalAlignment="Center" Text="Drag the target icon over the game window." />
</StackPanel>
</UserControl>
using System.Windows.Controls;
using System.Windows.Input;
namespace Ace.UI.Windows.Controls {
/// <summary>
/// Interaction logic for ProcessSelector.xaml
/// </summary>
public partial class ProcessSelector : UserControl {
public ProcessSelector() {
InitializeComponent();
}
private void Target_MouseDown(object sender, MouseButtonEventArgs e) {
Target.CaptureMouse();
Mouse.OverrideCursor = Cursors.Hand;
}
private void Target_MouseUp(object sender, MouseButtonEventArgs e) {
Target.ReleaseMouseCapture();
Mouse.OverrideCursor = null;
}
}
}
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Windows.Input;
using Prism.Commands;
namespace Ace.UI.Windows.ViewModels {
public class ProcessSelectorViewModel : INotifyPropertyChanged {
#region Imports
[DllImport("user32.dll")]
private static extern IntPtr WindowFromPoint(Point p);
[DllImport("user32.dll")]
private static extern IntPtr GetAncestor(IntPtr hwnd, uint flags);
[DllImport("user32.dll")]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int processId);
#endregion
#region Fields
private Process _selectedProcess;
#endregion
#region Properties
public ICommand SelectCommand { get; }
public Process SelectedProcess {
get { return _selectedProcess; }
private set { _selectedProcess = value; NotifyPropertyChanged(); }
}
#endregion
public ProcessSelectorViewModel() {
SelectCommand = new DelegateCommand(UpdateSelectedProcess);
}
private void UpdateSelectedProcess() {
var window = GetAncestor(WindowFromPoint(Control.MousePosition), 2);
GetWindowThreadProcessId(window, out var processId);
var process = Process.GetProcessById(processId);
if (process.Id != Process.GetCurrentProcess().Id)
SelectedProcess = process;
}
#region INotifyPropertyChanged Implementation
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] string propertyName = null) {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment