Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Panel elemen adalah komponen yang mengontrol penyajian elemen—ukuran dan dimensinya, posisinya, dan susunan konten anaknya. Windows Presentation Foundation (WPF) menyediakan sejumlah elemen yang telah Panel ditentukan sebelumnya serta kemampuan untuk membangun elemen kustom Panel .
| Judul | Description |
|---|---|
| Membuat Elemen Panel Kustom | Memperlihatkan cara membuat elemen panel kustom. |
| Mengambil alih Metode OnRender Panel | Menunjukkan cara mengambil alih metode OnRender dari Panel. |
| Mengatur Properti Tinggi dari sebuah Elemen | Memperlihatkan cara untuk mengatur properti tinggi dari sebuah elemen. |
| Setel Properti Lebar dari Suatu Elemen | Memperlihatkan cara mengatur properti lebar elemen. |
Gaya dan templat
Panel adalah kelas dasar abstrak yang tidak menentukan templat default atau tampilan visual. Kelas panel turunan mengimplementasikan gaya dan perilaku templat mereka sendiri.
Properti konten
Kontrol ini menggunakan Children properti sebagai properti isinya.
Bagian
Kontrol ini tidak menentukan bagian templat apa pun.
Keadaan visual
Kontrol ini tidak menentukan status visual apa pun.
Kelas Panel
Panel adalah kelas dasar untuk semua elemen yang menyediakan dukungan tata letak di Windows Presentation Foundation (WPF). Elemen turunan digunakan untuk memposisikan Panel dan menyusun elemen dalam Extensible Application Markup Language (XAML) dan kode.
WPF mencakup serangkaian implementasi panel turunan yang komprehensif yang memungkinkan banyak tata letak kompleks. Kelas turunan ini mengekspos properti dan metode yang memungkinkan sebagian besar skenario antarmuka pengguna (UI) standar. Pengembang yang tidak dapat menemukan perilaku pengaturan anak yang memenuhi kebutuhan mereka dapat membuat tata letak baru dengan mengesampingkan ArrangeOverride metode dan MeasureOverride .
Anggota umum panel
Semua Panel elemen mendukung properti ukuran dan posisi dasar yang ditentukan oleh FrameworkElement, termasuk Height, , Width, HorizontalAlignmentVerticalAlignment, Margin, dan LayoutTransform. Untuk informasi tambahan tentang properti pemposisian yang ditentukan oleh FrameworkElement, lihat Gambaran Umum Perataan, Margin, dan Padding.
Panel memaparkan properti tambahan yang sangat penting dalam memahami dan menggunakan tata letak. Properti Background ini digunakan untuk mengisi area antara batas elemen panel turunan dengan Brush. Children mewakili kumpulan elemen anak yang Panel terdiri dari. InternalChildren mewakili konten dari koleksi Children ditambah anggota yang dihasilkan oleh pengikatan data. Keduanya terdiri dari UIElementCollection elemen anak yang ditempatkan dalam induk Panel.
Panel juga mengekspos Panel.ZIndex properti terlampir yang dapat digunakan untuk mencapai urutan berlapis dalam turunan Panel. Anggota koleksi pada panel Children dengan nilai Panel.ZIndex yang lebih tinggi akan muncul di depan anggota yang memiliki nilai Panel.ZIndex yang lebih rendah. Ini sangat berguna untuk panel seperti Canvas dan Grid yang memungkinkan anak-anak untuk berbagi ruang koordinat yang sama.
Panel juga mendefinisikan OnRender metode , yang dapat digunakan untuk mengambil alih perilaku presentasi default dari Panel.
Properti yang dilampirkan
Elemen panel turunan memanfaatkan properti terlampir secara ekstensif. Properti terlampir adalah bentuk khusus properti dependensi yang tidak memiliki properti common language runtime (CLR) konvensional "wrapper". Properti terlampir memiliki sintaks khusus dalam Extensible Application Markup Language (XAML), yang dapat dilihat dalam beberapa contoh berikut.
Salah satu tujuan properti terlampir adalah untuk memungkinkan elemen turunan menyimpan nilai unik properti yang benar-benar ditentukan oleh elemen induk. Penerapan fungsionalitas ini adalah elemen anak menginformasikan kepada elemen induk bagaimana tampilan mereka di antarmuka pengguna (UI), yang sangat berguna untuk pengaturan tata letak aplikasi. Untuk informasi selengkapnya, lihat Gambaran Umum Properti Terlampir.
Elemen Panel Turunan
Banyak objek yang berasal dari Panel, tetapi tidak semuanya dimaksudkan untuk digunakan sebagai penyedia tata letak akar. Ada enam kelas panel yang ditentukan (Canvas, , DockPanel, GridStackPanel, VirtualizingStackPanel, dan WrapPanel) yang dirancang khusus untuk membuat antarmuka pengguna aplikasi.
Setiap elemen panel merangkum fungsionalitas khususnya sendiri, seperti yang terlihat dalam tabel berikut.
| Nama Elemen | Panel UI? | Description |
|---|---|---|
| Canvas | Yes | Menentukan area di mana Anda dapat memposisikan elemen turunan secara eksplisit dengan menggunakan koordinat relatif terhadap area Canvas. |
| DockPanel | Yes | Menentukan area di mana Anda dapat mengatur elemen turunan baik secara horizontal maupun vertikal relatif satu sama lain. |
| Grid | Yes | Menentukan area grid fleksibel yang terdiri dari kolom dan baris. Elemen turunan dari Grid dapat diposisikan secara tepat menggunakan properti Margin. |
| StackPanel | Yes | Mengatur elemen turunan menjadi satu baris yang dapat diorientasikan secara horizontal atau vertikal. |
| TabPanel | Tidak. | Menangani tata letak tombol-tombol tab dalam TabControl. |
| ToolBarOverflowPanel | Tidak. | Mengatur konten dalam ToolBar kendali. |
| UniformGrid | Tidak. | UniformGrid digunakan untuk mengatur anak-anak dalam kisi dengan semua ukuran sel yang sama. |
| VirtualizingPanel | Tidak. | Menyediakan kelas dasar untuk panel yang dapat "memvirtualisasi" koleksi anak-anak mereka. |
| VirtualizingStackPanel | Yes | Mengatur dan memvirtualisasi konten pada satu baris yang berorientasi horizontal atau vertikal. |
| WrapPanel | Yes | WrapPanel memposisikan elemen turunan secara berurutan dari kiri ke kanan, memindahkan konten ke baris berikutnya di batas kotak yang menampung. Urutan berikutnya terjadi secara berurutan dari atas ke bawah atau kanan ke kiri, tergantung pada nilai Orientation properti. |
Panel Antarmuka Pengguna
Ada enam kelas panel yang tersedia di WPF yang dioptimalkan untuk mendukung skenario UI: Canvas, , DockPanel, Grid, StackPanel, VirtualizingStackPanel, dan WrapPanel. Elemen panel ini mudah digunakan, serbaguna, dan cukup dapat diperluas untuk sebagian besar aplikasi.
Setiap elemen turunan Panel memperlakukan batasan ukuran secara berbeda. Memahami bagaimana Panel menangani batasan dalam arah horizontal atau vertikal dapat membuat tata letak lebih dapat diprediksi.
| Nama Panel | x-Dimension | y-Dimension |
|---|---|---|
| Canvas | Terbatas pada konten | Dibatasi pada konten |
| DockPanel | Terbatas | Terbatas |
| StackPanel (Orientasi Vertikal) | Terbatas | Terbatas pada konten |
| StackPanel (Orientasi Horizontal) | Dibatasi ke konten | Terbatas |
| Grid | Terbatas | Dibatasi, kecuali dalam kasus di mana Auto berlaku untuk baris dan kolom |
| WrapPanel | Dibatasi pada konten | Dibatasi ke konten |
Deskripsi dan contoh penggunaan yang lebih rinci dari masing-masing elemen ini dapat ditemukan di bawah ini.
Kanvas
Elemen ini Canvas memungkinkan penempatan konten sesuai dengan koordinat x- dan y- absolut. Elemen dapat digambar di lokasi yang unik; atau, jika elemen menempati koordinat yang sama, urutan munculnya dalam markup menentukan urutan di mana elemen digambar.
Canvas menyediakan dukungan tata letak yang paling fleksibel dari apa pun Panel. Properti Tinggi dan Lebar digunakan untuk menentukan area kanvas, dan elemen di dalamnya ditetapkan koordinat absolut relatif terhadap area induk Canvas. Empat properti terlampir, Canvas.Left, Canvas.Top, Canvas.Right dan Canvas.Bottom, memungkinkan kontrol halus penempatan objek dalam Canvas, memungkinkan pengembang untuk memosisikan dan mengatur elemen dengan tepat di layar.
ClipToBounds dalam Kanvas
Canvas dapat memposisikan elemen anak pada posisi apa pun di layar, bahkan pada koordinat yang berada di luar batas-batas yang ditentukan oleh Height dan Width. Selain itu, Canvas tidak terpengaruh oleh ukuran anak-anaknya. Akibatnya, dimungkinkan bagi elemen anak untuk melampaui elemen lain di luar persegi panjang pembatas induk Canvas. Perilaku default dari a Canvas adalah untuk memungkinkan anak-anak digambar di luar batas induk Canvas. Jika perilaku ini tidak diinginkan, ClipToBounds properti dapat diatur ke true. Ini menyebabkan Canvas terpangkas sesuai ukurannya sendiri.
Canvas adalah satu-satunya elemen tata letak yang memungkinkan anak-anak digambar di luar batasnya.
Perilaku ini diilustrasikan secara grafis dalam Sampel Perbandingan Properti Lebar.
DockPanel
Elemen DockPanel menggunakan properti DockPanel.Dock yang terlampir yang ditetapkan dalam elemen konten turunan untuk memosisikan konten di sepanjang tepi kontainer. Ketika DockPanel.Dock diatur ke Top atau Bottom, ia memposisikan elemen turunan di atas atau di bawah satu sama lain. Ketika DockPanel.Dock diatur ke Left atau Right, ia memposisikan elemen turunan ke kiri atau kanan satu sama lain. Properti LastChildFill menentukan posisi elemen akhir yang ditambahkan sebagai anak dari DockPanel.
Anda dapat menggunakan DockPanel untuk memosisikan sekelompok kontrol terkait, seperti sekumpulan tombol. Secara bergantian, Anda dapat menggunakannya untuk membuat UI "paned", mirip dengan yang ditemukan di Microsoft Outlook.
Pengaturan ukuran sesuai konten
Jika properti Height dan Width tidak ditentukan, DockPanel menyesuaikan ukuran dengan kontennya. Ukurannya dapat meningkat atau berkurang untuk mengakomodasi ukuran elemen anak. Namun, ketika properti ini ditentukan dan tidak ada lagi ruang untuk elemen turunan berikutnya yang ditentukan, DockPanel tidak menampilkan elemen turunan atau elemen turunan berikutnya dan tidak mengukur elemen turunan berikutnya.
LastChildFill
Secara default, anak terakhir dari DockPanel elemen akan "mengisi" ruang yang tersisa dan tidak dialokasikan. Jika perilaku ini tidak diinginkan, atur properti ke LastChildFillfalse.
Examples
Contoh berikut menunjukkan cara menggunakan Canvas untuk benar-benar memposisikan konten. Kode ini menghasilkan tiga kotak 100 piksel. Persegi pertama berwarna merah, dan posisi kiri atas (x, y) ditentukan sebagai (0, 0). Persegi kedua berwarna hijau, dan posisi kiri atasnya adalah (100, 100), tepat di bawah dan di sebelah kanan persegi pertama. Persegi ketiga berwarna biru, dan posisi kiri atasnya adalah (50, 50), sehingga mencakup kuadrian kanan bawah persegi pertama dan kuadrian kiri atas kedua. Karena persegi ketiga diletakkan terakhir, ia tampaknya berada di atas dua kotak lainnya—yaitu, bagian yang tumpang tindih mengasumsikan warna kotak ketiga.
// Create the application's main window
mainWindow = new Window ();
mainWindow.Title = "Canvas Sample";
// Create the Canvas
myParentCanvas = new Canvas();
myParentCanvas.Width = 400;
myParentCanvas.Height = 400;
// Define child Canvas elements
myCanvas1 = new Canvas();
myCanvas1.Background = Brushes.Red;
myCanvas1.Height = 100;
myCanvas1.Width = 100;
Canvas.SetTop(myCanvas1, 0);
Canvas.SetLeft(myCanvas1, 0);
myCanvas2 = new Canvas();
myCanvas2.Background = Brushes.Green;
myCanvas2.Height = 100;
myCanvas2.Width = 100;
Canvas.SetTop(myCanvas2, 100);
Canvas.SetLeft(myCanvas2, 100);
myCanvas3 = new Canvas();
myCanvas3.Background = Brushes.Blue;
myCanvas3.Height = 100;
myCanvas3.Width = 100;
Canvas.SetTop(myCanvas3, 50);
Canvas.SetLeft(myCanvas3, 50);
// Add child elements to the Canvas' Children collection
myParentCanvas.Children.Add(myCanvas1);
myParentCanvas.Children.Add(myCanvas2);
myParentCanvas.Children.Add(myCanvas3);
// Add the parent Canvas as the Content of the Window Object
mainWindow.Content = myParentCanvas;
mainWindow.Show ();
WindowTitle = "Canvas Sample"
'Create a Canvas as the root Panel
Dim myParentCanvas As New Canvas()
myParentCanvas.Width = 400
myParentCanvas.Height = 400
' Define child Canvas elements
Dim myCanvas1 As New Canvas()
myCanvas1.Background = Brushes.Red
myCanvas1.Height = 100
myCanvas1.Width = 100
Canvas.SetTop(myCanvas1, 0)
Canvas.SetLeft(myCanvas1, 0)
Dim myCanvas2 As New Canvas()
myCanvas2.Background = Brushes.Green
myCanvas2.Height = 100
myCanvas2.Width = 100
Canvas.SetTop(myCanvas2, 100)
Canvas.SetLeft(myCanvas2, 100)
Dim myCanvas3 As New Canvas()
myCanvas3.Background = Brushes.Blue
myCanvas3.Height = 100
myCanvas3.Width = 100
Canvas.SetTop(myCanvas3, 50)
Canvas.SetLeft(myCanvas3, 50)
' Add child elements to the Canvas' Children collection
myParentCanvas.Children.Add(myCanvas1)
myParentCanvas.Children.Add(myCanvas2)
myParentCanvas.Children.Add(myCanvas3)
' Add the parent Canvas as the Content of the Window Object
Me.Content = myParentCanvas
<Page WindowTitle="Canvas Sample" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Canvas Height="400" Width="400">
<Canvas Height="100" Width="100" Top="0" Left="0" Background="Red"/>
<Canvas Height="100" Width="100" Top="100" Left="100" Background="Green"/>
<Canvas Height="100" Width="100" Top="50" Left="50" Background="Blue"/>
</Canvas>
</Page>
Aplikasi yang dikompilasi menghasilkan UI baru yang terlihat seperti ini.
Contoh berikut menunjukkan cara mempartisi ruang menggunakan DockPanel. Lima Border elemen ditambahkan sebagai anak dari induk DockPanel. Masing-masing menggunakan properti penempatan DockPanel yang berbeda untuk membagi ruang. Elemen akhir "mengisi" ruang yang tersisa dan tidak dialokasikan.
// Create the application's main window
mainWindow = gcnew Window();
mainWindow->Title = "DockPanel Sample";
// Create the DockPanel
DockPanel^ myDockPanel = gcnew DockPanel();
myDockPanel->LastChildFill = true;
// Define the child content
Border^ myBorder1 = gcnew Border();
myBorder1->Height = 25;
myBorder1->Background = Brushes::SkyBlue;
myBorder1->BorderBrush = Brushes::Black;
myBorder1->BorderThickness = Thickness(1);
DockPanel::SetDock(myBorder1, Dock::Top);
TextBlock^ myTextBlock1 = gcnew TextBlock();
myTextBlock1->Foreground = Brushes::Black;
myTextBlock1->Text = "Dock = Top";
myBorder1->Child = myTextBlock1;
Border^ myBorder2 = gcnew Border();
myBorder2->Height = 25;
myBorder2->Background = Brushes::SkyBlue;
myBorder2->BorderBrush = Brushes::Black;
myBorder2->BorderThickness = Thickness(1);
DockPanel::SetDock(myBorder2, Dock::Top);
TextBlock^ myTextBlock2 = gcnew TextBlock();
myTextBlock2->Foreground = Brushes::Black;
myTextBlock2->Text = "Dock = Top";
myBorder2->Child = myTextBlock2;
Border^ myBorder3 = gcnew Border();
myBorder3->Height = 25;
myBorder3->Background = Brushes::LemonChiffon;
myBorder3->BorderBrush = Brushes::Black;
myBorder3->BorderThickness = Thickness(1);
DockPanel::SetDock(myBorder3, Dock::Bottom);
TextBlock^ myTextBlock3 = gcnew TextBlock();
myTextBlock3->Foreground = Brushes::Black;
myTextBlock3->Text = "Dock = Bottom";
myBorder3->Child = myTextBlock3;
Border^ myBorder4 = gcnew Border();
myBorder4->Width = 200;
myBorder4->Background = Brushes::PaleGreen;
myBorder4->BorderBrush = Brushes::Black;
myBorder4->BorderThickness = Thickness(1);
DockPanel::SetDock(myBorder4, Dock::Left);
TextBlock^ myTextBlock4 = gcnew TextBlock();
myTextBlock4->Foreground = Brushes::Black;
myTextBlock4->Text = "Dock = Left";
myBorder4->Child = myTextBlock4;
Border^ myBorder5 = gcnew Border();
myBorder5->Background = Brushes::White;
myBorder5->BorderBrush = Brushes::Black;
myBorder5->BorderThickness = Thickness(1);
TextBlock^ myTextBlock5 = gcnew TextBlock();
myTextBlock5->Foreground = Brushes::Black;
myTextBlock5->Text = "This content will Fill the remaining space";
myBorder5->Child = myTextBlock5;
// Add child elements to the DockPanel Children collection
myDockPanel->Children->Add(myBorder1);
myDockPanel->Children->Add(myBorder2);
myDockPanel->Children->Add(myBorder3);
myDockPanel->Children->Add(myBorder4);
myDockPanel->Children->Add(myBorder5);
// Add the parent Canvas as the Content of the Window Object
mainWindow->Content = myDockPanel;
mainWindow->Show();
// Create the application's main window
mainWindow = new Window ();
mainWindow.Title = "DockPanel Sample";
// Create the DockPanel
DockPanel myDockPanel = new DockPanel();
myDockPanel.LastChildFill = true;
// Define the child content
Border myBorder1 = new Border();
myBorder1.Height = 25;
myBorder1.Background = Brushes.SkyBlue;
myBorder1.BorderBrush = Brushes.Black;
myBorder1.BorderThickness = new Thickness(1);
DockPanel.SetDock(myBorder1, Dock.Top);
TextBlock myTextBlock1 = new TextBlock();
myTextBlock1.Foreground = Brushes.Black;
myTextBlock1.Text = "Dock = Top";
myBorder1.Child = myTextBlock1;
Border myBorder2 = new Border();
myBorder2.Height = 25;
myBorder2.Background = Brushes.SkyBlue;
myBorder2.BorderBrush = Brushes.Black;
myBorder2.BorderThickness = new Thickness(1);
DockPanel.SetDock(myBorder2, Dock.Top);
TextBlock myTextBlock2 = new TextBlock();
myTextBlock2.Foreground = Brushes.Black;
myTextBlock2.Text = "Dock = Top";
myBorder2.Child = myTextBlock2;
Border myBorder3 = new Border();
myBorder3.Height = 25;
myBorder3.Background = Brushes.LemonChiffon;
myBorder3.BorderBrush = Brushes.Black;
myBorder3.BorderThickness = new Thickness(1);
DockPanel.SetDock(myBorder3, Dock.Bottom);
TextBlock myTextBlock3 = new TextBlock();
myTextBlock3.Foreground = Brushes.Black;
myTextBlock3.Text = "Dock = Bottom";
myBorder3.Child = myTextBlock3;
Border myBorder4 = new Border();
myBorder4.Width = 200;
myBorder4.Background = Brushes.PaleGreen;
myBorder4.BorderBrush = Brushes.Black;
myBorder4.BorderThickness = new Thickness(1);
DockPanel.SetDock(myBorder4, Dock.Left);
TextBlock myTextBlock4 = new TextBlock();
myTextBlock4.Foreground = Brushes.Black;
myTextBlock4.Text = "Dock = Left";
myBorder4.Child = myTextBlock4;
Border myBorder5 = new Border();
myBorder5.Background = Brushes.White;
myBorder5.BorderBrush = Brushes.Black;
myBorder5.BorderThickness = new Thickness(1);
TextBlock myTextBlock5 = new TextBlock();
myTextBlock5.Foreground = Brushes.Black;
myTextBlock5.Text = "This content will Fill the remaining space";
myBorder5.Child = myTextBlock5;
// Add child elements to the DockPanel Children collection
myDockPanel.Children.Add(myBorder1);
myDockPanel.Children.Add(myBorder2);
myDockPanel.Children.Add(myBorder3);
myDockPanel.Children.Add(myBorder4);
myDockPanel.Children.Add(myBorder5);
// Add the parent Canvas as the Content of the Window Object
mainWindow.Content = myDockPanel;
mainWindow.Show ();
WindowTitle = "DockPanel Sample"
'Create a DockPanel as the root Panel
Dim myDockPanel As New DockPanel()
myDockPanel.LastChildFill = True
' Define the child content
Dim myBorder1 As New Border()
myBorder1.Height = 25
myBorder1.Background = Brushes.SkyBlue
myBorder1.BorderBrush = Brushes.Black
myBorder1.BorderThickness = New Thickness(1)
DockPanel.SetDock(myBorder1, Dock.Top)
Dim myTextBlock1 As New TextBlock()
myTextBlock1.Foreground = Brushes.Black
myTextBlock1.Text = "Dock = Top"
myBorder1.Child = myTextBlock1
Dim myBorder2 As New Border()
myBorder2.Height = 25
myBorder2.Background = Brushes.SkyBlue
myBorder2.BorderBrush = Brushes.Black
myBorder2.BorderThickness = New Thickness(1)
DockPanel.SetDock(myBorder2, Dock.Top)
Dim myTextBlock2 As New TextBlock()
myTextBlock2.Foreground = Brushes.Black
myTextBlock2.Text = "Dock = Top"
myBorder2.Child = myTextBlock2
Dim myBorder3 As New Border()
myBorder3.Height = 25
myBorder3.Background = Brushes.LemonChiffon
myBorder3.BorderBrush = Brushes.Black
myBorder3.BorderThickness = New Thickness(1)
DockPanel.SetDock(myBorder3, Dock.Bottom)
Dim myTextBlock3 As New TextBlock()
myTextBlock3.Foreground = Brushes.Black
myTextBlock3.Text = "Dock = Bottom"
myBorder3.Child = myTextBlock3
Dim myBorder4 As New Border()
myBorder4.Width = 200
myBorder4.Background = Brushes.PaleGreen
myBorder4.BorderBrush = Brushes.Black
myBorder4.BorderThickness = New Thickness(1)
DockPanel.SetDock(myBorder4, Dock.Left)
Dim myTextBlock4 As New TextBlock()
myTextBlock4.Foreground = Brushes.Black
myTextBlock4.Text = "Dock = Left"
myBorder4.Child = myTextBlock4
Dim myBorder5 As New Border()
myBorder5.Background = Brushes.White
myBorder5.BorderBrush = Brushes.Black
myBorder5.BorderThickness = New Thickness(1)
Dim myTextBlock5 As New TextBlock()
myTextBlock5.Foreground = Brushes.Black
myTextBlock5.Text = "This content will Fill the remaining space"
myBorder5.Child = myTextBlock5
' Add child elements to the DockPanel Children collection
myDockPanel.Children.Add(myBorder1)
myDockPanel.Children.Add(myBorder2)
myDockPanel.Children.Add(myBorder3)
myDockPanel.Children.Add(myBorder4)
myDockPanel.Children.Add(myBorder5)
Me.Content = myDockPanel
Lihat juga
- Gambaran Umum Perataan, Margin, dan Pengaturan Padding
- Gambaran Umum Properti Terlampir
- Membuat Sampel Panel Pembungkusan Konten Kustom
- Tata letak
- Tata Letak dan Desain
- ScrollViewer
- Gunakan Gambaran Umum Tata Letak Otomatis
- Walkthrough: Aplikasi desktop WPF pertama saya
- Sampel Galeri Kontrol WPF
- Sampel Galeri Tata Letak WPF
.NET Desktop feedback