I am trying to drag a rectangle on an empty canvas. However, when i drag it, it flashes/blinks constantly.
I put a debug and the x and y coordinates jump between where my mouse cursor currently is and several drags? behind? if that makes sense?
Example:
Update X: 638, Update Y: 382.66666666666663
Update X: 319.33333333333337, Update Y: 302.66666666666663
Update X: 638, Update Y: 382.66666666666663
Update X: 319.33333333333337, Update Y: 302.66666666666663
The issue now is in this area i think:
Canvas.Left="{Binding SelectionRectangle.X}"
Canvas.Top="{Binding SelectionRectangle.Y}"
If i set it to static numbers, the blinking stops but i cannot create a rectangle from any starting point.
Here is my View:
<Window x:Class="PdfPageTagger.Views.CanvasWindow"
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:PdfPageTagger.Views"
mc:Ignorable="d"
Loaded="Window_Loaded"
xmlns:vm="clr-namespace:PdfPageTagger.ViewModels"
Title="Canvas Viewer" >
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</Window.Resources>
<DockPanel Margin="10">
<Grid DockPanel.Dock="Top" Margin="10,0,10,10">
<Grid.RowDefinitions>
<RowDefinition Height="9*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Canvas x:Name="viewCanvas" Background="Black"
MouseLeftButtonDown="Canvas_MouseLeftButtonDown"
MouseMove="Canvas_MouseMove"
MouseLeftButtonUp="Canvas_MouseLeftButtonUp">
<Rectangle Stroke="Red" StrokeThickness="2"
Visibility="{Binding IsDrawing, Converter={StaticResource BooleanToVisibilityConverter}}"
Canvas.Left="{Binding SelectionRectangle.X}"
Canvas.Top="{Binding SelectionRectangle.Y}"
Width="{Binding SelectionRectangle.Width}"
Height="{Binding SelectionRectangle.Height}"/>
</Canvas>
</Grid>
</DockPanel>
</Window>
Here is the xaml.cs behind my view:
public partial class CanvasWindow : Window
{
public CanvasWindow()
{
InitializeComponent();
var vm = new CanvasWindowViewModel();
DataContext = vm;
vm.OnRequestClose += (s, e) => this.Close();
}
private async void Window_Loaded(object sender, RoutedEventArgs e)
{
// Get the ViewModel instance from the DataContext
if (DataContext is CanvasWindowViewModel viewModel)
{
await viewModel.WindowLoaded();
}
}
private void Canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var viewModel = DataContext as CanvasWindowViewModel;
if (viewModel != null)
{
viewModel.StartDrawingCommand.Execute(e);
}
}
private void Canvas_MouseMove(object sender, MouseEventArgs e)
{
var viewModel = DataContext as CanvasWindowViewModel;
if (viewModel != null)
{
viewModel.UpdateDrawingCommand.Execute(e);
}
}
private void Canvas_MouseLeftButtonUp(object sender, MouseEventArgs e)
{
var viewModel = DataContext as CanvasWindowViewModel;
if (viewModel != null)
{
viewModel.EndDrawingCommand.Execute(e);
}
}
}
Here is my ViewModel:
public class CanvasWindowViewModel : INotifyPropertyChanged
{
public ICommand StartDrawingCommand { get; }
public ICommand UpdateDrawingCommand { get; }
public ICommand EndDrawingCommand { get; }
public CanvasWindowViewModel()
{
StartDrawingCommand = new DelegateCommand<MouseButtonEventArgs>(StartDrawing);
UpdateDrawingCommand = new DelegateCommand<MouseEventArgs>(UpdateDrawing);
EndDrawingCommand = new DelegateCommand<MouseButtonEventArgs>(EndDrawing);
}
private Rect _selectionRectangle;
public Rect SelectionRectangle
{
get => _selectionRectangle;
set
{
_selectionRectangle = value;
RaisePropertyChanged(nameof(SelectionRectangle));
}
}
private bool _isDrawing;
public bool IsDrawing
{
get => _isDrawing;
set
{
_isDrawing = value;
RaisePropertyChanged(nameof(IsDrawing));
}
}
private Point _startPoint;
private void StartDrawing(MouseButtonEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
_startPoint = e.GetPosition(e.Source as IInputElement);
SelectionRectangle = new Rect(_startPoint, new Size(0, 0));
IsDrawing = true;
Debug.WriteLine($"Start X: {_startPoint.X}, Start Y: {_startPoint.Y}");
}
}
private void UpdateDrawing(MouseEventArgs e)
{
if (IsDrawing)
{
var currentPoint = e.GetPosition(e.Source as IInputElement);
var x = Math.Min(currentPoint.X, _startPoint.X);
var y = Math.Min(currentPoint.Y, _startPoint.Y);
var width = Math.Abs(currentPoint.X - _startPoint.X);
var height = Math.Abs(currentPoint.Y - _startPoint.Y);
SelectionRectangle = new Rect(x, y, width, height);
Debug.WriteLine($"Update X: {currentPoint.X}, Update Y: {currentPoint.Y}");
}
}
private void EndDrawing(MouseButtonEventArgs e)
{
if (e.LeftButton == MouseButtonState.Released)
{
IsDrawing = false;
Debug.WriteLine("Drawing Ended");
}
}
public ObservableCollection<ImageSource> Pages { get; } = new ObservableCollection<ImageSource>();
public event EventHandler OnRequestClose;
public async Task WindowLoaded()
{
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void RaisePropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}