Search code examples
c#wpf

WPF Canvas using all screens


I've the following setup on my monitors:

Monitors

I'm working on a screenshot app with C# - WPF and when i try to place the canvas on the monitor 3, it still loads in primary windows (monitor 2).

I tried Canvas.SetLeft and Canvas.SetTop using VirtualScreen.Left and VirtualScreen.Top (The values are OK, same values with the same situacion in another app in Java), but didn't work.

 private void InitializeEditor()
 {
     var left = System.Windows.Forms.SystemInformation.VirtualScreen.Left;
     var top = System.Windows.Forms.SystemInformation.VirtualScreen.Top;
     var width = System.Windows.Forms.SystemInformation.VirtualScreen.Width;
     var height = System.Windows.Forms.SystemInformation.VirtualScreen.Height;

     MainCanvas = new Canvas();
     MainCanvas.Background = Brushes.Black;
     Content = MainCanvas;

     MainImage = new Image();
     Canvas.SetLeft(MainImage, 0);
     Canvas.SetTop(MainImage, 0);
     //Canvas.SetLeft(MainImage, left);
     //Canvas.SetTop(MainImage, top);


     SecondImage = new Image();

     Canvas.SetLeft(SecondImage, 0);
     Canvas.SetTop(SecondImage, 0);
     //Canvas.SetLeft(SecondImage, left);
     //Canvas.SetTop(SecondImage, top);
     SecondImage.Opacity = 0.6;


     SelectedArea = new();
     screenshotAreaPickingState = new(this);
     screenshotAreaMovingState = new(this);

     freePenDrawingState = new FreePenDrawingState(MainCanvas);
     lineState = new LineDrawingState(MainCanvas);
     rectangleState = new RectangleDrawingState(MainCanvas, this);
     arrowDrawingState = new ArrowDrawingState(MainCanvas);
     textDrawingState = new TextDrawingState(MainCanvas);

     var grid = new Grid();

     if (this.Content != MainCanvas)
     {
         grid.Children.Add(MainCanvas);
     }

     CreateRectMenu();

 }

Also Tried changing windows properties, but didn't work too

this.WindowStartupLocation = System.Windows.WindowStartupLocation.Manual;
this.Left = System.Windows.Forms.SystemInformation.VirtualScreen.Left;
this.Top = System.Windows.Forms.SystemInformation.VirtualScreen.Top;
this.Width = System.Windows.Forms.SystemInformation.VirtualScreen.Width;
this.Height = System.Windows.Forms.SystemInformation.VirtualScreen.Height;
this.WindowStyle = WindowStyle.None;
this.WindowState = WindowState.Minimized;
this.Visibility = Visibility.Hidden;
this.Topmost = true;

Solution

  • Unfortunately, there is no easy way to manipulate monitors in WPF. I am showing you an example based on the helper Nuget package https://www.nuget.org/packages/WpfScreenHelper

    In the example, you can select any monitor in the ListBox and the window will be transferred to the selected monitor.

    using WpfScreenHelper;
    
        public class MonitorHelper
        {
            private Screen? selectedScreen;
    
            public MonitorHelper()
            {
                Screens = Screen.AllScreens.ToArray();
            }
    
            public Screen[] Screens { get; }
    
            public Screen? SelectedScreen
            {
                get => selectedScreen;
                set
                {
                    selectedScreen = value;
    
                    if (Window is not null)
                    {
                        Window.Left = value.WpfBounds.Left;
                        Window.Top = value.WpfBounds.Top;
                    }
                }
            }
    
            public Window? Window { get; set; }
        }
    
    <Window x:Class="Core2024.SO.mr_k3p.question78800290.SelectMonitorWindow"
            x:Name="wind"
            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:Core2024.SO.mr_k3p.question78800290"
            xmlns:wpfscreenhelper="clr-namespace:WpfScreenHelper;assembly=WpfScreenHelper"
            mc:Ignorable="d"
            Title="SelectMonitorWindow" Height="450" Width="1000"
            DataContext="{DynamicResource helper}">
        <Window.Resources>
            <local:MonitorHelper x:Key="helper"
                                 Window="{x:Reference wind}"/>
            <DataTemplate DataType="{x:Type wpfscreenhelper:Screen}">
                <UniformGrid>
                    <TextBlock Text="{Binding Bounds, StringFormat='Bounds={0}'}" Margin="10 0"/>
                    <TextBlock Text="{Binding DeviceName, StringFormat='DeviceName={0}'}" Margin="10 0"/>
                    <TextBlock Text="{Binding Primary, StringFormat='Primary={0}'}" Margin="10 0"/>
                    <TextBlock Text="{Binding ScaleFactor, StringFormat='ScaleFactor={0}'}" Margin="10 0"/>
                    <TextBlock Text="{Binding WorkingArea, StringFormat='WorkingArea={0}'}" Margin="10 0"/>
                    <TextBlock Text="{Binding WpfWorkingArea, StringFormat='WpfWorkingArea={0}'}" Margin="10 0"/>
                    <TextBlock Text="{Binding WpfBounds, StringFormat='WpfBounds={0}'}" Margin="10 0"/>
                    <TextBlock Text="{Binding WpfWorkingArea, StringFormat='WpfWorkingArea={0}'}" Margin="10 0"/>
                </UniformGrid>
            </DataTemplate>
        </Window.Resources>
        <StackPanel Margin="10">
            <StackPanel Background="LightGreen">
                <TextBlock Text="Full Virtual Area" FontWeight="Bold" HorizontalAlignment="Center"/>
                <UniformGrid Rows="1">
                    <TextBlock Text="{Binding Path=(SystemParameters.VirtualScreenLeft), StringFormat='Left={0}'}"/>
                    <TextBlock Text="{Binding Path=(SystemParameters.VirtualScreenTop), StringFormat='Top={0}'}"/>
                    <TextBlock Text="{Binding Path=(SystemParameters.VirtualScreenWidth), StringFormat='Width={0}'}"/>
                    <TextBlock Text="{Binding Path=(SystemParameters.VirtualScreenHeight), StringFormat='Height={0}'}"/>
                 </UniformGrid>
            </StackPanel>
            <ListBox ItemsSource="{Binding Screens}"
                     SelectedItem="{Binding SelectedScreen}"/>
        </StackPanel>
    </Window>