Bagaimana cara mendapatkan ukuran layar saat ini di WPF?

90

Saya tahu saya bisa mengetahui ukuran layar utama dengan menggunakan

System.Windows.SystemParameters.PrimaryScreenWidth;
System.Windows.SystemParameters.PrimaryScreenHeight;

Tapi bagaimana cara mendapatkan ukuran layar saat ini? (Pengguna Multi-Layar tidak selalu menggunakan layar utama dan tidak semua layar menggunakan resolusi yang sama, bukan?)

Akan menyenangkan untuk dapat mengakses ukuran dari XAML, tetapi melakukannya dari kode (C #) sudah cukup.

Nils
sumber
1
Tentukan "saat ini". Sebuah jendela bisa berada di lebih dari satu layar sekaligus.
Jim Balter

Jawaban:

15

Sejauh yang saya tahu tidak ada fungsi WPF asli untuk mendapatkan dimensi monitor saat ini. Sebagai gantinya Anda dapat PInvoke native multiple display monitor functions , membungkusnya dalam kelas terkelola dan mengekspos semua properti yang Anda butuhkan untuk menggunakannya dari XAML.

Anvaka
sumber
Itulah yang saya takuti - kebutuhan untuk P / Memanggil barang atau mengakses System.Windows.Forms.Screen entah bagaimana. Dan saat melakukannya, saya selalu perlu menghitung "piksel independen perangkat" ... Terima kasih.
Nils
Ya ... Mungkin fungsi SystemParameters.ConvertPixel () juga akan membantu Anda. Ini internal, tapi Reflector tidak peduli
:)
76

Saya membuat sedikit pembungkus di sekitar Layar dari System.Windows.Forms, saat ini semuanya berfungsi ... Namun, tidak yakin tentang "piksel perangkat independen".

public class WpfScreen
{
    public static IEnumerable<WpfScreen> AllScreens()
    {
        foreach (Screen screen in System.Windows.Forms.Screen.AllScreens)
        {
            yield return new WpfScreen(screen);
        }
    }

    public static WpfScreen GetScreenFrom(Window window)
    {
        WindowInteropHelper windowInteropHelper = new WindowInteropHelper(window);
        Screen screen = System.Windows.Forms.Screen.FromHandle(windowInteropHelper.Handle);
        WpfScreen wpfScreen = new WpfScreen(screen);
        return wpfScreen;
    }

    public static WpfScreen GetScreenFrom(Point point)
    {
        int x = (int) Math.Round(point.X);
        int y = (int) Math.Round(point.Y);

        // are x,y device-independent-pixels ??
        System.Drawing.Point drawingPoint = new System.Drawing.Point(x, y);
        Screen screen = System.Windows.Forms.Screen.FromPoint(drawingPoint);
        WpfScreen wpfScreen = new WpfScreen(screen);

        return wpfScreen;
    }

    public static WpfScreen Primary
    {
        get { return new WpfScreen(System.Windows.Forms.Screen.PrimaryScreen); }
    }

    private readonly Screen screen;

    internal WpfScreen(System.Windows.Forms.Screen screen)
    {
        this.screen = screen;
    }

    public Rect DeviceBounds
    {
        get { return this.GetRect(this.screen.Bounds); }
    }

    public Rect WorkingArea
    {
        get { return this.GetRect(this.screen.WorkingArea); }
    }

    private Rect GetRect(Rectangle value)
    {
        // should x, y, width, height be device-independent-pixels ??
        return new Rect
                   {
                       X = value.X,
                       Y = value.Y,
                       Width = value.Width,
                       Height = value.Height
                   };
    }

    public bool IsPrimary
    {
        get { return this.screen.Primary; }
    }

    public string DeviceName
    {
        get { return this.screen.DeviceName; }
    }
}
Nils
sumber
Terima kasih untuk pembungkus kecil yang hebat ini, perhatikan bahwa global :: Rect perlu diubah menjadi Rect biasa saat saya menggunakan WPF 3.5.
Andy Dent
1
Saya suka ini. Tentu perlu sedikit kerja keras, tetapi saya tidak berharap menemukan solusi 100%.
jeff
4
Bekerja dengan baik. Saya baru saja memperluas metode GetRect untuk mengembalikan Rect dalam piksel independen perangkat: Private Rect GetRect (Nilai persegi panjang) {var pixelWidthFactor = SystemParameters.WorkArea.Width / this.screen.WorkingArea.Width; var pixelHeightFactor = SystemParameters.WorkArea.Height / this.screen.WorkingArea.Height; kembalikan Rect baru {X = value.X * pixelWidthFactor, Y = value.Y * pixelHeightFactor, Width = value.Width * pixelWidthFactor, Height = value.Height * pixelHeightFactor}; }
Jürgen Bayer
1
Saya percaya menambahkan kode dari @ JürgenBayer akan lebih meningkatkan jawaban Anda. Saya memiliki masalah dengan piksel independen perangkat dan kode dari Jürgen menyelesaikannya. Terima kasih semuanya.
Bruno V
3
@ Jürgen: Saya yakin metode Anda hanya berfungsi dalam keadaan yang sangat spesifik. Jika "this.screen" memiliki rasio aspek yang berbeda dari monitor utama (yang selalu digunakan metode Anda sebagai referensi alih-alih monitor saat ini), Anda akan mendapatkan faktor skala yang berbeda untuk lebar dan tinggi yang menyebabkan dimensi layar salah. Jika layar saat ini memiliki pengaturan DPI yang berbeda dari layar utama, semua batasannya akan salah. Di sistem saya, setiap nilai dari Rect yang dikembalikan (sangat) salah.
Wilford
27

Ini sobat. Ini hanya akan memberi Anda lebar dan tinggi area kerja

System.Windows.SystemParameters.WorkArea.Width
System.Windows.SystemParameters.WorkArea.Height
Guilherme Ferreira
sumber
13
"Mendapat ukuran area kerja di monitor layar utama." - bukan yang saya cari ....
Nils
12

Ini akan memberi Anda layar saat ini berdasarkan kiri atas jendela cukup panggil this.CurrentScreen () untuk mendapatkan info di layar saat ini.

using System.Windows;
using System.Windows.Forms;

namespace Common.Helpers
{
    public static class WindowHelpers
     {
        public static Screen CurrentScreen(this Window window)
         {
             return Screen.FromPoint(new System.Drawing.Point((int)window.Left,(int)window.Top));
         }
     }
}
EJ
sumber
Pengguna mencari dimensi layar saat ini, bukan layar utama.
greggannicott
3
ini mengembalikan layar saat ini, berdasarkan posisi kiri atas jendela tempat Anda memanggil fungsi helper. Tetapi saya pasti melewatkan sesuatu untuk pertanyaan ini, berdasarkan skor jawaban saya.
EJ
Mungkin greggannicott bermaksud mengirim komentarnya ke salah satu jawaban lain, karena itu sama sekali tidak relevan dengan jawaban ini.
Jim Balter
@ jim-balter Voted Up - Sebenarnya ini adalah jawaban terbaik di sini, saya memerlukan Layar untuk mendapatkan area kerja dan kemudian memastikan dialog saya tidak melebihi batas, saya akan memposting solusi saya di sini. Kudos to EJ untuk jawaban cepat ke intinya.
Juv
^ komentar aneh.
Jim Balter
4

Saya juga membutuhkan dimensi layar saat ini, khususnya area Kerja, yang mengembalikan persegi panjang tidak termasuk lebar Taskbar.

Saya menggunakannya untuk memposisikan ulang jendela, yang dibuka ke kanan dan ke bawah ke tempat mouse ditempatkan. Karena jendelanya cukup besar, dalam banyak kasus itu keluar dari batas layar. Kode berikut didasarkan pada jawaban @ej: Ini akan memberi Anda layar saat ini ... . Perbedaannya adalah saya juga menunjukkan algoritme reposisi saya, yang saya asumsikan sebenarnya adalah intinya.

Kode:

using System.Windows;
using System.Windows.Forms;

namespace MySample
{

    public class WindowPostion
    {
        /// <summary>
        /// This method adjust the window position to avoid from it going 
        /// out of screen bounds.
        /// </summary>
        /// <param name="topLeft">The requiered possition without its offset</param>
        /// <param name="maxSize">The max possible size of the window</param>
        /// <param name="offset">The offset of the topLeft postion</param>
        /// <param name="margin">The margin from the screen</param>
        /// <returns>The adjusted position of the window</returns>
        System.Drawing.Point Adjust(System.Drawing.Point topLeft, System.Drawing.Point maxSize, int offset, int margin)
        {
            Screen currentScreen = Screen.FromPoint(topLeft);
            System.Drawing.Rectangle rect = currentScreen.WorkingArea;

            // Set an offset from mouse position.
            topLeft.Offset(offset, offset);

            // Check if the window needs to go above the task bar, 
            // when the task bar shadows the HUD window.
            int totalHight = topLeft.Y + maxSize.Y + margin;

            if (totalHight > rect.Bottom)
            {
                topLeft.Y -= (totalHight - rect.Bottom);

                // If the screen dimensions exceed the hight of the window
                // set it just bellow the top bound.
                if (topLeft.Y < rect.Top)
                {
                    topLeft.Y = rect.Top + margin;
                }
            }

            int totalWidth = topLeft.X + maxSize.X + margin;
            // Check if the window needs to move to the left of the mouse, 
            // when the HUD exceeds the right window bounds.
            if (totalWidth > rect.Right)
            {
                // Since we already set an offset remove it and add the offset 
                // to the other side of the mouse (2x) in addition include the 
                // margin.
                topLeft.X -= (maxSize.X + (2 * offset + margin));

                // If the screen dimensions exceed the width of the window
                // don't exceed the left bound.
                if (topLeft.X < rect.Left)
                {
                    topLeft.X = rect.Left + margin;
                }
            }

            return topLeft;
        }
    }
}

Beberapa penjelasannya:

1) topLeft - position of the top left at the desktop (works                     
   for multi screens - with different aspect ratio).                            
            Screen1              Screen2                                        
        ─  ┌───────────────────┐┌───────────────────┐ Screen3                   
        ▲  │                   ││                   │┌─────────────────┐  ─     
        │  │                   ││                   ││   ▼-            │  ▲     
   1080 │  │                   ││                   ││                 │  │     
        │  │                   ││                   ││                 │  │ 900 
        ▼  │                   ││                   ││                 │  ▼     
        ─  └──────┬─────┬──────┘└──────┬─────┬──────┘└──────┬────┬─────┘  ─     
                 ─┴─────┴─            ─┴─────┴─            ─┴────┴─             
           │◄─────────────────►││◄─────────────────►││◄───────────────►│        
                   1920                 1920                1440                
   If the mouse is in Screen3 a possible value might be:                        
   topLeft.X=4140 topLeft.Y=195                                                 
2) offset - the offset from the top left, one value for both                    
   X and Y directions.                                                          
3) maxSize - the maximal size of the window - including its                     
   size when it is expanded - from the following example                        
   we need maxSize.X = 200, maxSize.Y = 150 - To avoid the expansion            
   being out of bound.                                                          

   Non expanded window:                                                         
   ┌──────────────────────────────┐ ─                                           
   │ Window Name               [X]│ ▲                                           
   ├──────────────────────────────┤ │                                           
   │         ┌─────────────────┐  │ │ 100                                       
   │  Text1: │                 │  │ │                                           
   │         └─────────────────┘  │ │                                           
   │                         [▼]  │ ▼                                           
   └──────────────────────────────┘ ─                                           
   │◄────────────────────────────►│                                             
                 200                                                            

   Expanded window:                                                             
   ┌──────────────────────────────┐ ─                                           
   │ Window Name               [X]│ ▲                                           
   ├──────────────────────────────┤ │                                           
   │         ┌─────────────────┐  │ │                                           
   │  Text1: │                 │  │ │                                           
   │         └─────────────────┘  │ │ 150                                       
   │                         [▲]  │ │                                           
   │         ┌─────────────────┐  │ │                                           
   │  Text2: │                 │  │ │                                           
   │         └─────────────────┘  │ ▼                                           
   └──────────────────────────────┘ ─                                           
   │◄────────────────────────────►│                                             
                 200                                                            
4) margin - The distance the window should be from the screen                   
   work-area - Example:                                                          
   ┌─────────────────────────────────────────────────────────────┐ ─            
   │                                                             │ ↕ Margin     
   │                                                             │ ─            
   │                                                             │              
   │                                                             │              
   │                                                             │              
   │                          ┌──────────────────────────────┐   │              
   │                          │ Window Name               [X]│   │              
   │                          ├──────────────────────────────┤   │              
   │                          │         ┌─────────────────┐  │   │              
   │                          │  Text1: │                 │  │   │              
   │                          │         └─────────────────┘  │   │              
   │                          │                         [▲]  │   │              
   │                          │         ┌─────────────────┐  │   │              
   │                          │  Text2: │                 │  │   │              
   │                          │         └─────────────────┘  │   │              
   │                          └──────────────────────────────┘   │ ─            
   │                                                             │ ↕ Margin     
   ├──────────────────────────────────────────────────┬──────────┤ ─            
   │[start] [♠][♦][♣][♥]                              │en│ 12:00 │              
   └──────────────────────────────────────────────────┴──────────┘              
   │◄─►│                                                     │◄─►│              
    Margin                                                    Margin            

* Note that this simple algorithm will always want to leave the cursor          
  out of the window, therefor the window will jumps to its left:                
  ┌─────────────────────────────────┐        ┌─────────────────────────────────┐
  │                  ▼-┌──────────────┐      │  ┌──────────────┐▼-             │
  │                    │ Window    [X]│      │  │ Window    [X]│               │
  │                    ├──────────────┤      │  ├──────────────┤               │
  │                    │       ┌───┐  │      │  │       ┌───┐  │               │
  │                    │  Val: │   │  │ ->   │  │  Val: │   │  │               │
  │                    │       └───┘  │      │  │       └───┘  │               │
  │                    └──────────────┘      │  └──────────────┘               │
  │                                 │        │                                 │
  ├──────────────────────┬──────────┤        ├──────────────────────┬──────────┤
  │[start] [♠][♦][♣]     │en│ 12:00 │        │[start] [♠][♦][♣]     │en│ 12:00 │
  └──────────────────────┴──────────┘        └──────────────────────┴──────────┘
  If this is not a requirement, you can add a parameter to just use             
  the margin:                                                                   
  ┌─────────────────────────────────┐        ┌─────────────────────────────────┐
  │                  ▼-┌──────────────┐      │                ┌─▼-───────────┐ │
  │                    │ Window    [X]│      │                │ Window    [X]│ │
  │                    ├──────────────┤      │                ├──────────────┤ │
  │                    │       ┌───┐  │      │                │       ┌───┐  │ │
  │                    │  Val: │   │  │ ->   │                │  Val: │   │  │ │
  │                    │       └───┘  │      │                │       └───┘  │ │
  │                    └──────────────┘      │                └──────────────┘ │
  │                                 │        │                                 │
  ├──────────────────────┬──────────┤        ├──────────────────────┬──────────┤
  │[start] [♠][♦][♣]     │en│ 12:00 │        │[start] [♠][♦][♣]     │en│ 12:00 │
  └──────────────────────┴──────────┘        └──────────────────────┴──────────┘
* Supports also the following scenarios:
  1) Screen over screen:
       ┌─────────────────┐  
       │                 │
       │                 │
       │                 │
       │                 │
       └─────────────────┘
     ┌───────────────────┐ 
     │                   │ 
     │  ▼-               │ 
     │                   │ 
     │                   │ 
     │                   │ 
     └──────┬─────┬──────┘ 
           ─┴─────┴─       
  2) Window bigger than screen hight or width
     ┌─────────────────────────────────┐        ┌─────────────────────────────────┐ 
     │                                 │        │ ┌──────────────┐                │
     │                                 │        │ │ Window    [X]│                │
     │                  ▼-┌────────────│─┐      │ ├──────────────┤ ▼-             │
     │                    │ Window    [│]│      │ │       ┌───┐  │                │
     │                    ├────────────│─┤ ->   │ │  Val: │   │  │                │ 
     │                    │       ┌───┐│ │      │ │       └───┘  │                │
     │                    │  Val: │   ││ │      │ │       ┌───┐  │                │
     │                    │       └───┘│ │      │ │  Val: │   │  │                │
     ├──────────────────────┬──────────┤ │      ├──────────────────────┬──────────┤
     │[start] [♠][♦][♣]     │en│ 12:00 │ │      │[start] [♠][♦][♣]     │en│ 12:00 │
     └──────────────────────┴──────────┘ │      └──────────────────────┴──────────┘
                          │       ┌───┐  │        │       └───┘  │
                          │  Val: │   │  │        └──────────────┘
                          │       └───┘  │
                          └──────────────┘


     ┌─────────────────────────────────┐             ┌─────────────────────────────────┐     
     │                                 │             │                                 │ 
     │                                 │             │ ┌───────────────────────────────│───┐
     │    ▼-┌──────────────────────────│────────┐    │ │ W▼-dow                        │[X]│
     │      │ Window                   │     [X]│    │ ├───────────────────────────────│───┤
     │      ├──────────────────────────│────────┤    │ │       ┌───┐      ┌───┐      ┌─┤─┐ │
     │      │       ┌───┐      ┌───┐   │  ┌───┐ │ -> │ │  Val: │   │ Val: │   │ Val: │ │ │ │
     │      │  Val: │   │ Val: │   │ Va│: │   │ │    │ │       └───┘      └───┘      └─┤─┘ │
     │      │       └───┘      └───┘   │  └───┘ │    │ └───────────────────────────────│───┘
     ├──────────────────────┬──────────┤────────┘    ├──────────────────────┬──────────┤
     │[start] [♠][♦][♣]     │en│ 12:00 │             │[start] [♠][♦][♣]     │en│ 12:00 │     
     └──────────────────────┴──────────┘             └──────────────────────┴──────────┘     
  • Saya tidak punya pilihan selain menggunakan format kode (jika tidak, spasi putih akan hilang).
  • Awalnya ini muncul dalam kode di atas sebagai <remark><code>...</code></remark>
Juv
sumber
4

Luangkan waktu untuk memindai melalui anggota SystemParameters.

  • VirtualScreenWidth
  • VirtualScreenHeight

Ini bahkan memperhitungkan posisi relatif layar.

Hanya diuji dengan dua monitor.

dana
sumber
9
dana - Saya belum menguji ini, tetapi bukankah VirtualScreen * mengembalikan ukuran penuh semua layar? - Saya secara khusus Membutuhkan ukuran satu layar (yang di mana jendela saat ini berada).
Nils
1
VirtualScreen tampaknya mengacu pada ukuran semua layar
Thomas
1
Satu tambang ini mengembalikan ukuran semua 4 layar saya digabungkan.
DJ van Wyk
3

Mengapa tidak menggunakan ini saja?

var interopHelper = new WindowInteropHelper(System.Windows.Application.Current.MainWindow);
var activeScreen = Screen.FromHandle(interopHelper.Handle);
Matteoz
sumber
Layarnya adalah Windows. Bentuknya bukan WPF - tetapi ini adalah titik awal. Jika Anda melihat solusi yang saya gunakan saat itu ( stackoverflow.com/a/2118993/180156 ) inilah yang saya lakukan - namun saya membungkusnya System.Windows.Forms.Screenuntuk mengatasi piksel yang tidak bergantung perangkat
Nils
3

Jika Anda sudah terbiasa menggunakan kelas System.Windows.Forms maka Anda bisa menambahkan referensi kelas System.Windows.Forms ke proyek Anda:

Solution Explorer -> Referensi -> Tambah Referensi ... -> (Assemblies: Framework) -> gulir ke bawah dan periksa perakitan System.Windows.Forms -> OK .

Sekarang Anda dapat menambahkan menggunakan System.Windows.Forms; pernyataan dan gunakan layar dalam proyek wpf Anda seperti sebelumnya.

Phương Trần
sumber
Sejauh ini, ini adalah solusi termudah. Saya bertanya-tanya - selain menambahkan rakitan yang agak besar, apakah ada alasan bagus untuk tidak melakukannya dengan cara ini?
AeonOfTime
1

Saya mengerti tuntutannya. Masalahnya, ada Metode WPF untuk mendapatkan nilai-nilai itu - tapi ya, salah satu kontributornya benar, tidak secara langsung. Solusinya bukanlah untuk mendapatkan semua penyelesaian tersebut, tetapi untuk mengubah pendekatan awal sesuai dengan Desain dan Pengembangan yang bersih.

A) Atur Jendela Utama awal ke Layar

B) Dapatkan Nilai untuk ActualWindow termasuk banyak Metode WPF yang berguna

C) Anda dapat menambahkan Windows sebanyak yang Anda suka untuk perilaku yang Anda inginkan, seperti mengubah ukuran, meminimalkan apa pun… tetapi sekarang Anda selalu dapat mengakses Layar yang Dimuat dan Dirender

Harap berhati-hati dengan contoh berikut, ada beberapa Kode di sekitar yang mengharuskan untuk menggunakan pendekatan semacam itu, namun itu harus berhasil (Ini akan memberi Anda Poin untuk setiap Sudut Layar Anda): Contoh Bekerja di Single, Monitor Ganda dan Resolusi berbeda (Dalam Kelas Jendela Utama Primal):

InitializeComponent();
[…]
ActualWindow.AddHandler(Window.LoadedEvent, new RoutedEventHandler(StartUpScreenLoaded));

Acara yang Dirutekan:

private void StartUpScreenLoaded(object sender, RoutedEventArgs e)
    {
        Window StartUpScreen = sender as Window;

        // Dispatcher Format B:
        Dispatcher.Invoke(new Action(() =>
        {
            // Get Actual Window on Loaded
            StartUpScreen.InvalidateVisual();
            System.Windows.Point CoordinatesTopRight = StartUpScreen.TranslatePoint(new System.Windows.Point((StartUpScreen.ActualWidth), (0d)), ActualWindow);
            System.Windows.Point CoordinatesBottomRight = StartUpScreen.TranslatePoint(new System.Windows.Point((StartUpScreen.ActualWidth), (StartUpScreen.ActualHeight)), ActualWindow);
            System.Windows.Point CoordinatesBottomLeft = StartUpScreen.TranslatePoint(new System.Windows.Point((0d), (StartUpScreen.ActualHeight)), ActualWindow);

            // Set the Canvas Top Right, Bottom Right, Bottom Left Coordinates
            System.Windows.Application.Current.Resources["StartUpScreenPointTopRight"] = CoordinatesTopRight;
            System.Windows.Application.Current.Resources["StartUpScreenPointBottomRight"] = CoordinatesBottomRight;
            System.Windows.Application.Current.Resources["StartUpScreenPointBottomLeft"] = CoordinatesBottomLeft;
        }), DispatcherPriority.Loaded);
    }
Dororo
sumber
1

Jika Anda menggunakan jendela layar penuh (memiliki WindowState = WindowState.Maximized, WindowStyle = WindowStyle.None), Anda dapat membungkus isinya System.Windows.Controls.Canvasseperti ini:

<Canvas Name="MyCanvas" Width="auto" Height="auto">
...
</Canvas>

Kemudian Anda dapat menggunakan MyCanvas.ActualWidthdanMyCanvas.ActualHeight mendapatkan resolusi layar saat ini, dengan pengaturan DPI yang diperhitungkan dan di unit independen perangkat. Itu tidak menambahkan margin apa pun seperti jendela yang dimaksimalkan itu sendiri.

(Canvas menerima UIElements sebagai anak-anak, jadi Anda harus dapat menggunakannya dengan konten apa pun.)

zvizesna
sumber
0

Jendela Tengah pada layar di XAML WindowStartupLocation="CenterOwner"lalu panggil di WindowLoaded ()

double ScreenHeight = 2 * (Top + 0.5 * Height);

mikesl
sumber
-4
double screenWidth = System.Windows.SystemParameters.PrimaryScreenWidth;
double screenhight= System.Windows.SystemParameters.PrimaryScreenHeight;
Rahul chalkhure
sumber
4
Seperti jawaban sebelumnya, ini hanya untuk Layar utama . Saya membutuhkan layar saat ini .
Nils
-4

Ini bekerja dengan

this.Width = System.Windows.SystemParameters.VirtualScreenWidth;
this.Height = System.Windows.SystemParameters.VirtualScreenHeight;

Diuji pada 2 monitor.

Hoang
sumber
jika Anda melihat jawaban dari 18 Mei '10 pada 15:52 - yang persis sama dengan milik Anda, Anda akan melihat bahwa VirtualScreenmencakup semua layar - jadi ini tidak akan pernah berhasil jika Anda memiliki lebih dari satu layar!
Nils