היסטוריית עדכונים (גרסה ראשונה, פורסמה בתאריך 18 Mar 2026)
- פרסום ראשון
לצטט את המאמר הזה(DOI: 10.5281/zenodo.22173630)
מאמר זה מאוחסן בארכיון Zenodo. להלן גם ה-DOI שתמיד מפנה לגרסה האחרונה וגם ה-DOI המקובע לגרסה שאתם קוראים.
Go Komura (2026). WinForms, WPF או WinUI — טבלת החלטה מעשית. KomuraSoft LLC. https://doi.org/10.5281/zenodo.22173630 https://comcomponent.com/he/blog/winforms-wpf-winui-decision-table/
- DOI (הגרסה האחרונה)
- 10.5281/zenodo.22173630
- DOI (הגרסה הזו)
- 10.5281/zenodo.22173631
קהל יעד: מפתחים שבונים אפליקציות desktop ל-Windows ב-C# / .NET, ומי שמחליט על הבחירה הטכנולוגית. הנחה: משתמשים ב-.NET הנוכחי (לא ב-.NET Framework), ופלטפורמת היעד היא Windows בלבד. איך לקרוא: למסקנה בלבד — פרקים 1 ו-3; למדיניות המשך על אפליקציה קיימת — פרק 7; להכרעה אחרונה — פרק 8.
כשבונים אפליקציית desktop ל-Windows ב-C# / .NET, מה שמסתבך בכל פעם מחדש בלי רעש הוא הבחירה בין WinForms, WPF ו-WinUI.
הדבר המסוכן כאן הוא בחירה מעורפלת כמו:
- WinUI כי הוא הכי חדש
- WinForms כי אליו הכי רגילים
- WPF כי הוא נראה איפשהו באמצע
flowchart TB
accTitle: הסכנה שבבחירה מעורפלת
accDescr: תרשים שמראה שבחירה מעורפלת כמו WinUI כי הוא חדש, WinForms כי אליו רגילים, ו-WPF כי הוא נראה באמצע, מסוכנת, ושבעבודה בפועל בוחנים לפי צירים ברורים יותר.
w1["WinUI כי הוא חדש"] --> w4["בחירה מעורפלת"]
w2["WinForms כי אליו רגילים"] --> w4
w3["WPF כי הוא נראה באמצע"] --> w4
w4 --> w5["בעבודה בפועל בוחנים לפי צירים ברורים"]
איור 1: לא “חדש, מוכר או נראה באמצע” — בוחרים לפי צירים ברורים.
בעבודה בפועל, הצירים שצריך לבחון ברורים יותר:
- פיתוח חדש, או המשך של אפליקציה קיימת
- האם המסכים מבוססי טפסי קלט, או שצריך UI עשיר יותר
- האם UI מודרני ואופייני ל-Windows הוא ערך המוצר עצמו
- איך מטפלים ב-deployment, עדכונים ותפעול ארגוני
- האם הצוות עובד בסגנון Designer, או בסגנון XAML / MVVM
במאמר הזה נרכז את כל זה בטבלת החלטה אחת שאפשר לסרוק במהירות. לצורך המאמר, WinUI מתייחס בעיקר ל-WinUI 3 + Windows App SDK.12
בנוסף, שלושתם ייעודיים כולם ל-Windows בלבד. אם גם macOS / Linux בתמונה, זו מלכתחילה הגדרת בעיה אחרת.341
flowchart TB
accTitle: שלושתם ייעודיים ל-Windows בלבד
accDescr: תרשים שמראה ש-WinForms, WPF ו-WinUI כולם ייעודיים ל-Windows בלבד, ושאם גם macOS או Linux בתמונה, זו הגדרת בעיה אחרת לגמרי.
t1["WinForms"] --> t4["כולם ייעודיים ל-Windows"]
t2["WPF"] --> t4
t3["WinUI"] --> t4
t4 -.-> t5["macOS / Linux — הגדרת בעיה אחרת"]
איור 2: שלושתם ייעודיים ל-Windows, ופלטפורמות חוצות דורשות הגדרת בעיה אחרת.
1. קודם המסקנה (במשפט אחד)
בניסוח גס אבל שימושי בעבודה בפועל, זה נראה כך:
- אם יש אפליקציית WinForms קיימת גדולה, קודם בודקים המשך עם WinForms
- אם יש אפליקציית WPF קיימת גדולה, קודם בודקים המשך עם WPF
- לכלי פנימי חדש בקנה מידה קטן-בינוני, שמבוסס על פקדים סטנדרטיים ומסכי קלט ורוצים לבנות מהר, WinForms עדיין די חזק35
- ליישום עסקי חדש בקנה מידה בינוני-גדול, עם הרבה מסכים, שרוצים להשתמש בו כראוי ב-data binding, style, template, command ו-MVVM, WPF לרוב הבחירה הבטוחה ביותר467
- למוצר חדש ייעודי ל-Windows, שבו UI מודרני של Windows, Fluent וחוויית Windows עדכנית קשורים ישירות לערך המוצר, WinUI אפשרות טובה12
- אם רוצים רק להשתמש ב-Windows API עדכניים, WinUI אינו הכרחי. גם WPF / WinForms יכולים לשלב פיצ’רים של Windows App SDK28910
- לבחור מתוך הנחה ש“אפשר להכניס WinUI בהדרגה בהמשך” מסוכן במקצת. מעבר הדרגתי מלוכלך יותר ממה שנשמע1011
בקיצור, זה בערך כך:
- אם יש הרבה קוד קיים, קודם משאירים את אותו קו
- בפיתוח חדש, לבניית טפסים סטנדרטיים מהר — WinForms
- בפיתוח חדש, ליישום עסקי ל-Windows שגדל לאורך זמן — WPF
- בפיתוח חדש, כש-UI מודרני של Windows הוא עצמו דרישה — WinUI
- אם רוצים רק Windows App SDK, לא עוברים ישר לגמרי ל-WinUI
בחירת framework היא לא רק בחירה בטכנולוגיית UI, אלא גם בחירה של deployment, תפעול, עלות למידה ועלות מעבר. אם קובעים את זה רק לפי “חדש / ישן”, זה חוזר בהמשך כתכנון deployment ועלות תחזוקה.
flowchart TB
accTitle: איך מגיעים למסקנה
accDescr: תרשים שמראה שאם יש הרבה קוד קיים משאירים את אותו קו, ובפיתוח חדש בוחרים WinForms לטפסים סטנדרטיים, WPF ליישום עסקי שגדל לאורך זמן, ו-WinUI כש-UI מודרני הוא דרישה.
r1{"יש הרבה קוד קיים?"} -->|"כן"| r2["משאירים את אותו קו"]
r1 -->|"לא, פיתוח חדש"| r3{"מבוסס טפסים סטנדרטיים?"}
r3 -->|"כן"| r4["WinForms"]
r3 -->|"לא"| r5{"UI מודרני הוא דרישה?"}
r5 -->|"לא"| r6["WPF, יישום עסקי ארוך טווח"]
r5 -->|"כן"| r7["WinUI"]
r7 -.-> r8["אם רק SDK — לא עוברים לגמרי ל-WinUI"]
איור 3: לפי סדר קוד קיים, אופי המסך ודרישת UI מודרני, המסקנה כמעט נקבעת מאליה.
ב-diagram, solid line מציינת relation שתמיד מתקיים ו-dashed line מציינת relation מותנה (התנאים מופיעים בהסבר של כל relation ב-detail page). הרשימה המלאה של ה-relations (סה”כ 24, כולל evidence ו-certainty) וההגדרות של ה-concepts המרכזיים נמצאות ב-detail page של ה-knowledge map (ביפנית). Data: JSON-LD / Turtle
2. שלוש הטכנולוגיות שהמאמר מדבר עליהן
קודם מיישרים מינוח. הקיצורים שחוזרים לאורך המאמר מפורטים כאן מראש.
| מונח | פירוש | בגסות |
|---|---|---|
| XAML | eXtensible Application Markup Language | שפת markup מבוססת XML לכתיבה הצהרתית של מבנה המסך. משמשת את WPF ואת WinUI |
| Designer | Windows Forms Designer | פיצ’ר ב-Visual Studio לגרירת פקדים ובניית מסך. התוצאה נשמרת כקוד בקובץ *.Designer.cs |
| Data Binding | data binding | מנגנון שמקשר בין property של המסך ל-property בצד הנתונים, כך שכשאחד משתנה השני עוקב אחריו |
| MVVM | Model-View-ViewModel | תבנית תכנון שמפרידה בין המסך (View), המצב והפקודות של המסך (ViewModel), ולוגיקת העסק והנתונים (Model). ה-View וה-ViewModel מחוברים דרך Data Binding |
| Fluent | Fluent Design System | מערכת העיצוב של Microsoft שקובעת את המראה וההתנהגות של Windows 11. WinUI מניח אותה כברירת מחדל |
| Windows App SDK | — | קבוצת ספריות הפיתוח העדכנית ל-Windows, כולל WinUI. יש בה גם פיצ’רים שאינם UI, ואפשר להוסיף אותה גם לאפליקציות קיימות של WPF / WinForms / Win32 |
| XAML Islands | — | מנגנון להטמעת פקדי XAML חדשים בחלק בלבד מאפליקציה קיימת של WPF / WinForms / Win32. הרחבה בסעיף 5.3.3 |
| MSIX | — | פורמט חבילת האפליקציה של Windows. התקנה, עדכון והסרה מטופלים על ידי מנגנון של מערכת ההפעלה |
| package identity | זהות חבילה | מצב שבו Windows יכול לזהות לאיזו חבילת אפליקציה שייך ה-process. חלק מפיצ’רי Windows, כמו התראות ושיוכי קבצים, לא עובדים בלעדיו |
| טכנולוגיה | בגסות | הציר החזק |
|---|---|---|
| WinForms | UI מסורתי של .NET ל-Windows, שקל לבנות בו טפסים מהר עם ה-Designer של Visual Studio | בניית מסכים מהירה, פקדים סטנדרטיים, ניצול קוד קיים |
| WPF | UI ייעודי ל-Windows, שקל לבנות בו UI עשיר בעזרת XAML, data binding, style, template ו-command | יישום עסקי בינוני-גדול, MVVM, קלות ארגון המסכים |
| WinUI | UI מודרני ונייטיבי ל-Windows, מעל Windows App SDK | Fluent, חוויית Windows עדכנית, DPI גבוה, UI מוצרי מודרני |
WinForms מתואר גם ב-Microsoft Learn כ-framework עם פקדים, גרפיקה, data binding וקלט משתמש, שקל לבנות בו אפליקציה בעזרת ה-Designer של Visual Studio בגרירה-ושחרור.3
WPF הוא UI framework עם גמישות גבוהה, שכולל ציור וקטורי שאינו תלוי ברזולוציה, XAML, data binding, style / template, 2D / 3D ואנימציה.4
WinUI, חלק מ-Windows App SDK, הוא UI framework עדכני ל-Windows שמניח DPI גבוה, קלט מודרני, אנימציה חלקה וחוויית Fluent.12 יש לו גם מסלול רגיל של data binding / MVVM.12
חשוב לזכור כאן ש-Windows App SDK ו-WinUI אינם אותו דבר. WinUI הוא חלק ה-UI framework בתוך Windows App SDK, אבל את Windows App SDK עצמו אפשר להוסיף גם לאפליקציות קיימות של WPF / WinForms / Win32.210
לכן,
- להשתמש ב-WinUI
- להשתמש בפיצ’רים של Windows App SDK
הן החלטות שנראות דומות, אבל נפרדות. אם דנים בהן כשהן מעורבבות, “האם להעביר את ה-UI” ו”האם להוסיף פיצ’רים” נשמעים כאותו נושא, וקשה להגיע למסקנה.
flowchart TB
accTitle: Windows App SDK ו-WinUI אינם זהים
accDescr: תרשים שמראה ש-WinUI הוא חלק ה-UI framework בתוך Windows App SDK, ושאת Windows App SDK עצמו אפשר להוסיף גם ל-WPF, WinForms ו-Win32, ולכן ההחלטה על WinUI וההחלטה על פיצ'רי SDK נפרדות.
sdk["Windows App SDK"] --> ui["WinUI, חלק ה-UI framework"]
sdk -.-> ex["אפשר להוסיף גם ל-WPF / WinForms / Win32"]
ui --> d1["החלטה: להשתמש ב-WinUI"]
ex --> d2["החלטה: להשתמש בפיצ'רי SDK"]
d1 --> d3["נראות דומות אבל נפרדות"]
d2 --> d3
איור 4: “להשתמש ב-WinUI” ו”להשתמש בפיצ’רים של Windows App SDK” הן החלטות נפרדות.
3. טבלת החלטה אחת לסריקה
קודם, הטבלה הכי שימושית לעבודה בפועל.
| מצב | הבחירה הראשונה | סיבה |
|---|---|---|
| תחזוקה, המשך פיתוח או עדכון ל-.NET של אפליקציית WinForms קיימת | המשך WinForms | קל לנצל מסכים קיימים, נכסי Designer ונכסי פקדים |
| תחזוקה, המשך פיתוח או עדכון ל-.NET של אפליקציית WPF קיימת | המשך WPF | קל לנצל את ה-XAML, ה-Binding, ה-MVVM ומבנה המסכים כמות שהם |
| פיתוח חדש, כלי פנימי, מסך הגדרות, מסך ניהול, מבוסס טפסי קלט | WinForms | פקדים סטנדרטיים במרכז — עלייה מהירה |
| פיתוח חדש, הרבה מסכים, מצב מורכב, רוצים style / template / MVVM | WPF | קל להפריד אחריות בין מסכים ולארגן את ה-UI |
| פיתוח חדש, UI מודרני ואופייני ל-Windows הוא עצמו הדרישה | WinUI | קל להתקרב ל-Fluent ולחוויית Windows עדכנית |
| להישאר עם WPF / WinForms קיימים ולהשתמש ב-Toast / Windowing / App Lifecycle וכדומה | ה-framework הנוכחי + Windows App SDK | לרוב אין צורך במעבר מלא של ה-UI כדי לקבל פיצ’רי Windows עדכניים |
| תלות כבדה ב-COM / ActiveX / פקדי צד שלישי ישנים | קרוב ל-framework הקיים | עלות מעבר התלות כבדה עוד לפני עניין ה-UI |
| מושפעים חזק משיקולי deployment, עדכון ותפעול ארגוני | לתת עדיפות ל-WPF / WinForms, ו-WinUI לבדוק תכנון deployment מוקדם | ב-WinUI צריך לבחון מוקדם את הנחות Windows App SDK / packaging |
| רוצים חוצה-פלטפורמות בעתיד | לשקול מחדש כולל אפשרויות מחוץ לשלושתם | שלושתם ייעודיים ל-Windows בלבד |
הטבלה הזו כמעט מספיקה, אבל נשארות שתי נקודות שקשה להחליט לגביהן.
- ביישום עסקי חדש ל-Windows, לאיזה מבין WinForms ו-WPF להתקרב
- כשיש WPF / WinForms קיימים, האם כדאי לעבור ל-WinUI
שתי הנקודות האלה קל יותר להכריע תוך התבוננות בטבלת ההשוואה שבהמשך.
flowchart TB
accTitle: שתי הנקודות שנשארות אחרי טבלת ההחלטה
accDescr: תרשים שמראה שגם עם טבלת החלטה אחת נשארות שתי שאלות — האם ליישום עסקי חדש להתקרב ל-WinForms או WPF, והאם לעבור ל-WinUI כשיש אפליקציות קיימות — וששתיהן נבחנות בטבלת ההשוואה הבאה.
hyo["טבלת ההחלטה"] --> n1["WinForms או WPF ליישום חדש"]
hyo --> n2["האם לעבור ל-WinUI כשיש קוד קיים"]
n1 --> hik["בוחנים בטבלת ההשוואה"]
n2 --> hik
איור 5: שתי הנקודות שנשארות אחרי הטבלה נבחנות בטבלת ההשוואה שבהמשך.
4. טבלת השוואה לפי היבטים
זו לא טבלת עליונות רשמית, אלא השוואה שמוטה מאוד לעבודה בפועל.
| היבט | WinForms | WPF | WinUI |
|---|---|---|---|
| בניית טופס קלט קטן במהירות | ◎ | ○ | ○ |
| כלי פנימי שמבוסס פקדים סטנדרטיים | ◎ | ○ | △〜○ |
| התאמה ל-data binding / MVVM | △ | ◎ | ○〜◎ |
| style / template וגמישות המסך | △ | ◎ | ◎ |
| קרבה לקוד desktop קיים ב-Windows | ◎ | ○ | △ |
| אופי Windows מודרני | △ | ○ | ◎ |
| המשך תחזוקה ושיפוץ הדרגתי של מסכים קיימים | ◎ | ◎ | △ |
| רוצים רק להוסיף פיצ’רי Windows App SDK | ○ | ○ | ◎ |
| קלות תכנון ה-deployment / עדכון / תפעול | ○ | ○ | △〜○ |
| בניית “UI מוצרי חדש וייעודי ל-Windows שגדל לאורך זמן” | △ | ○ | ◎ |
הטריק בקריאה הוא לא מה הכי חזק, אלא מה יוצר הכי פחות חיכוך.
לדוגמה, עבור:
- כלי הגדרות פנימי
- מסך הגדרות מכשיר
- רשימה, פירוט, חיפוש, הגדרות, כפתורים
- יציבות תפעולית ומהירות שיפוץ חשובים יותר מהמראה
WinForms עדיין הגיוני לגמרי.
לעומת זאת, עבור:
- הרבה מסכים
- הרבה החלפות מצב תצוגה
- רוצים להפריד בין View ללוגיקה
- רוצים לקשר שינויי נתונים ל-UI בטבעיות
- רוצים לשלוט ב-UI דרך style / template
ולבסוף, עבור:
- רוצים להניח מראה אופייני ל-Windows 11
- רוצים לנצל את Fluent כראוי
- רוצים להניח DPI גבוה, מגע, ו-API חלונות מודרני
- פיתוח חדש שבו הרושם של ה-UI כמוצר ייעודי ל-Windows חשוב
flowchart TB
accTitle: בוחרים לפי כמות החיכוך הנמוכה ביותר
accDescr: תרשים שמראה שהקריטריון הוא לא מה הכי חזק אלא מה יוצר הכי פחות חיכוך, וש-WinForms טבעי לכלי פנימי מבוסס פקדים, WPF להרבה מסכים עם MVVM, ו-WinUI כש-Fluent וחוויית Windows עדכנית הם הבסיס.
k0["מה יוצר הכי פחות חיכוך"] --> k1["כלי ארגוני — פקדים סטנדרטיים"]
k0 --> k2["הרבה מסכים — רוצים MVVM"]
k0 --> k3["Fluent — חוויית Windows עדכנית"]
k1 --> k4["WinForms"]
k2 --> k5["WPF"]
k3 --> k6["WinUI"]
איור 6: לא “מה הכי חזק” אלא “מה יוצר הכי פחות חיכוך” — כך מחלקים בין השלושה.
4.1 לראות את פערי הגמישות בקוד מינימלי
השורה “התאמה ל-data binding / MVVM” בטבלה למעלה קשה לתפוס במילים בלבד. לכן נציג זה לצד זה, בקוד מינימלי, מה משתנה כשכותבים את אותו מסך ב-WinForms וב-WPF.
נבנה מסך עם “תיבת טקסט אחת וכפתור שמירה אחד” בלבד.
WinForms: ה-Designer מייצר *.Designer.cs, וב-event handler שולפים את הערך מהמסך.
// MainForm.Designer.cs — הצד שמייצר ה-Designer. לא כותבים כאן ידנית
private System.Windows.Forms.TextBox nameTextBox;
private System.Windows.Forms.Button saveButton;
private void InitializeComponent()
{
this.nameTextBox = new System.Windows.Forms.TextBox();
this.saveButton = new System.Windows.Forms.Button();
this.SuspendLayout();
this.nameTextBox.Location = new System.Drawing.Point(12, 12);
this.nameTextBox.Size = new System.Drawing.Size(200, 23);
this.saveButton.Location = new System.Drawing.Point(218, 12);
this.saveButton.Size = new System.Drawing.Size(75, 23);
this.saveButton.Text = "保存";
this.saveButton.Click += new System.EventHandler(this.SaveButton_Click);
this.Controls.Add(this.nameTextBox);
this.Controls.Add(this.saveButton);
this.ResumeLayout(false);
}
// MainForm.cs — הצד שכותבים ידנית
public partial class MainForm : Form
{
private readonly EditorService _service;
public MainForm(EditorService service)
{
_service = service;
InitializeComponent();
}
private void SaveButton_Click(object sender, EventArgs e)
{
// שולפים את הערך ישירות מהפקד של המסך ומעבירים אותו
_service.Save(this.nameTextBox.Text);
}
}
WPF: ב-XAML כותבים רק “עם מה זה מחובר”, וה-Binding מטפל בהכנסה ובהוצאה של הערך.
<!-- MainWindow.xaml -->
<Window x:Class="MyApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="編集" Width="360" Height="120">
<StackPanel Orientation="Horizontal" Margin="12">
<TextBox Width="200"
Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" />
<Button Width="75" Margin="6,0,0,0" Content="保存"
Command="{Binding SaveCommand}" />
</StackPanel>
</Window>
// MainWindow.xaml.cs — אם שוכחים להעביר DataContext, ה-Binding לא עושה כלום
public partial class MainWindow : Window
{
public MainWindow(EditorService service)
{
InitializeComponent();
this.DataContext = new MainViewModel(service);
}
}
// MainViewModel.cs — הצד שלא מכיר את המסך. אפשר לכתוב כאן גם unit test
public sealed class MainViewModel : INotifyPropertyChanged
{
private readonly EditorService _service;
private string _name = string.Empty;
public MainViewModel(EditorService service)
{
_service = service;
SaveCommand = new RelayCommand(() => _service.Save(Name));
}
public string Name
{
get => _name;
set
{
if (_name == value) return;
_name = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Name)));
}
}
public ICommand SaveCommand { get; }
public event PropertyChangedEventHandler PropertyChanged;
}
RelayCommand הוא class קטן שמממש ICommand, נמצא גם בספריות כמו CommunityToolkit.Mvvm, וגם אפשר לכתוב אותו בעצמכם בכ-20 שורות.
אם סופרים רק שורות, ל-WPF יש יותר. ההבדל האמיתי מתחיל מכאן.
| WinForms | WPF | |
|---|---|---|
| היכן שולפים ערך מהמסך | קוראים ישירות nameTextBox.Text בתוך ה-event handler |
property בשם Name. לא נוגעים ב-View |
| unit test לפעולת השמירה | צריך להקים Form | אפשר ליצור MainViewModel ישירות עם new ולקרוא לו |
| הצגת אותו שדה קלט במסך נוסף | ממקמים מחדש את הפקד, וכותבים מחדש גם את ה-handler | מציבים View אחר על אותו ViewModel |
| אחידות מראה בכל המסכים | מיישרים כל property של כל פקד בנפרד | Style / Template במקום אחד |
אם יש 3 מסכים, WinForms מהיר יותר; אם יש 30 מסכים, WPF קליל יותר — זו המשמעות המעשית של ההבדל.
flowchart TB
accTitle: ההבדל בזרימת הערך
accDescr: תרשים שמראה שב-WinForms ה-event handler שולף ערך ישירות מהפקד ומעביר לשירות, ואילו ב-WPF ה-Binding מחבר בין ה-View ל-ViewModel, וה-ViewModel שלא מכיר את המסך קורא לשירות.
subgraph wf["WinForms"]
a1["פקד ב-View"] --> a2["event handler"]
a2 --> a3["קורא ישירות לשירות"]
end
subgraph wp["WPF"]
b1["XAML של ה-View"] --> b2["Binding"]
b2 --> b3["ViewModel"]
b3 --> b4["קורא לשירות"]
end
a3 -.-> c1["3 מסכים — מהיר"]
b4 -.-> c2["30 מסכים — עדיין קליל"]
איור 7: ב-WinForms שולפים ערך ישירות, וב-WPF ה-Binding מעביר את התפקיד ל-ViewModel.
5. לאיזה סוג פרויקט כל אחד מתאים
5.1 WinForms
WinForms נוטה לזכות בזלזול לא הוגן, אבל בנקודה אחת — בניית מסכים עסקיים מהירה, מבוססת פקדים סטנדרטיים — הוא עדיין לא זניח.35
הוא מתאים במיוחד לפרויקטים כמו:
- כלי הגדרות פנימי
- מסכי הגדרות למכשירים, מכשירי מדידה וכלי ניטור
- מסכי ניהול, מסכי חיפוש, רשימה + פירוט
- פרויקטים עם הרבה קוד WinForms קיים
- צוותים עם תרבות חזקה של בניית מסכים ב-Designer
היתרון של WinForms הוא שאפשר להגיע למסך קרוב למוצר מוגמר בקצב סביר, בלי להביא אידיאולוגיה מסובכת. טופס, כפתור, תווית, תיבת טקסט, data grid. אם זו זירת המשחק, WinForms מסוגל להתחרות היטב.
עם זאת, החולשות ברורות:
- רוצים אחידות מראה גדולה בכל המסכים
- רוצים לשלוט ב-UI דרך style ו-template
- רוצים לטפל בשינויי מצב מורכבים בעיקר דרך data binding
- רוצים להפריד יפה את הלוגיקה של המסך
בנקודות האלה, WPF או WinUI פשוטים יותר.
בבניית אפליקציה גדולה עם WinForms, בלי תשומת לב זה בקלות הופך לג’ונגל של event handlers. לכן, אם בוחרים ב-WinForms, כדאי לקבוע מראש לפחות:
- לשמור על אחריות קטנה לכל מסך
- להפריד ביחידות UserControl
- להיות מודעים לגבול מקביל ל-Presenter / ViewModel
- לא לכתוב לוגיקה עסקית ישירות בתוך אירועי המסך
flowchart TB
accTitle: להימנע מג'ונגל event handlers
accDescr: תרשים שמראה שאפליקציית WinForms גדולה הופכת בקלות לג'ונגל של event handlers, ולכן כדאי לקבוע מראש לשמור על אחריות קטנה למסך, להפריד ביחידות UserControl, ולהיות מודעים לגבול Presenter/ViewModel.
mo["אפליקציית WinForms גדולה"] --> ha["הופכת בקלות לג'ונגל handlers"]
ha --> p1["לשמור אחריות קטנה למסך"]
ha --> p2["להפריד ביחידות UserControl"]
ha --> p3["להיות מודעים לגבול"]
p3 -.-> p4["לא לכתוב לוגיקה עסקית באירועי מסך"]
איור 8: אפליקציית WinForms גדולה נשארת שקטה אם קובעים מראש כללי הפרדת אחריות.
עוד דבר חשוב מאוד בעבודה בפועל: גם אם רוצים להשתמש ב-Windows App SDK, אין צורך לזרוק את WinForms. גם רשמית קיים מסלול להוסיף פיצ’רי Windows App SDK לאפליקציית WinForms קיימת.910
כלומר, אפשר לבחור ב-WinForms כך ש-
- ה-UI נשאר כמות שהוא
- רק פיצ’רי Windows הדרושים מתעדכנים
וזה נקודת נחיתה ריאלית.
flowchart TB
accTitle: לעדכן בלי לזרוק את WinForms
accDescr: תרשים שמראה שהרצון להשתמש ב-Windows App SDK אינו מחייב לזרוק את WinForms, ושיש נקודת נחיתה ריאלית שבה ה-UI נשאר כמות שהוא ורק הפיצ'רים הדרושים מתעדכנים.
g1["רוצים Windows App SDK"] --> g2["אין צורך לזרוק WinForms"]
g2 --> g3["ה-UI נשאר כמות שהוא"]
g2 --> g4["מתעדכנים רק הפיצ'רים הדרושים"]
g3 --> g5["נקודת נחיתה ריאלית"]
g4 --> g5
איור 9: אפשר לשמר את ה-UI של WinForms ולשלב רק את הפיצ’רים הדרושים של Windows.
5.2 WPF
WPF, כשמסתכלים עליו כ-UI של .NET ל-Windows desktop, הוא הליבה המאוזנת ביותר.4
היתרונות ברורים:
- אפשר לכתוב מסך הצהרתית ב-XAML
- Data Binding חזק
- אפשר להשתמש ב-Style / Template
- אפשר להשתמש ב-Command
- קל להפריד בין View ללוגיקה
- קל לארגן מסכים בקנה מידה בינוני-גדול
גם בתיעוד הרשמי של WPF, data binding מתואר כפיצ’ר מרכזי, וה-command מסודר כמנגנון שמפריד בין קלט ללוגיקת הביצוע.67
לכן, הוא מתאים לפרויקטים כמו:
- יישום עסקי עם הרבה מסכים
- הרבה תצוגות רשימה, פירוט, עריכה, חיפוש ומצב
- אפליקציית Windows שכמה אנשים מתחזקים לאורך זמן
- רוצים להפריד בין View ללוגיקה
- רוצים להפריד מראש בין אחריות המראה לאחריות ההתנהגות, לקראת שיפוצים עתידיים
- WinForms נראה כמו שיהפוך למסך כבד מהר
כשמתלבטים ביישום עסקי חדש ייעודי ל-Windows, WPF עדיין המועמד הראשון הבטוח. לפסול אותו כי “הוא ישן” זה קצת גס.
flowchart TB
accTitle: המועמד הראשון הבטוח ליישום עסקי חדש
accDescr: תרשים שמראה שביישום עסקי בינוני-גדול ל-Windows עם הרבה מסכים, שרוצים להפריד View מלוגיקה ומתוחזק לאורך זמן על ידי כמה אנשים, WPF עדיין המועמד הראשון הבטוח.
j1["יישום עסקי עם הרבה מסכים"] --> j4["WPF — המועמד הראשון הבטוח"]
j2["רוצים להפריד View מלוגיקה"] --> j4
j3["תחזוקה ארוכת טווח על ידי כמה אנשים"] --> j4
j4 -.-> j5["לפסול כי 'ישן' זה גס"]
איור 10: ביישום עסקי חדש עם הרבה מסכים ותחזוקה ארוכת טווח, WPF עדיין הבחירה הבטוחה.
ולמעשה, כש-
- יש קוד WPF קיים
- יש ידע קיים ב-XAML / MVVM
- Fluent אינו הראשון בעדיפות
- אבל רוצים לתכנן UI נקי יותר מ-WinForms
WPF לרוב הבחירה ההגיונית ביותר.
כמובן שגם ל-WPF יש מוזרויות:
- XAML מסובך מדי הופך לקשה לקריאה
- יותר מדי פקדים או templates מותאמים אישית מכבידים על התחזוקה
- מדיניות “לפתור הכול עם Binding” יכולה להקשות דווקא על מעקב אחר זרימת העיבוד
הבעיות האלה קיימות, אבל זה לא ש-WPF רע — זה יותר שכלי גמיש, אם משתמשים בו ברשלנות, גם התגובה שלו חזקה יותר.
גם ב-WPF אפשר להוסיף חלק מהפיצ’רים של Windows App SDK. כלומר, יש דרך לשלב פיצ’רי Windows בזמן שנשארים עם WPF.810
לכן, לרוב, בעבודה בפועל מנצחת הגישה של
- להתקרב ל-.NET הנוכחי עם WPF
- להוסיף רק את פיצ’רי Windows הדרושים דרך Windows App SDK
- לארגן מחדש את המבנה החל מהפיצ’רים הגדולים החדשים
יותר מ-
- לזרוק את כל ה-WPF ולעבור לגמרי ל-WinUI
flowchart TB
accTitle: הדרגתיות מנצחת מעבר מלא
accDescr: תרשים שמראה שבמקום לזרוק את WPF ולעבור לגמרי ל-WinUI, עדיף להתקרב ל-.NET הנוכחי, להוסיף רק פיצ'רים דרושים דרך Windows App SDK, ולארגן מחדש החל מהפיצ'רים הגדולים החדשים.
z1["WPF מתקרב ל-.NET הנוכחי"] --> z2["מוסיפים רק פיצ'רים דרושים דרך SDK"]
z2 --> z3["מארגנים מחדש מהפיצ'רים הגדולים החדשים"]
z3 -.-> z4["מנצח לרוב מעל מעבר מלא"]
איור 11: במקום מעבר מלא, להתקרב ל-.NET הנוכחי ולהוסיף פיצ’רים בהדרגה — זו הדרך שמנצחת יותר.
5.3 WinUI
WinUI הוא הבחירה המודרנית העיקרית לבניית אפליקציה חדשה ייעודית ל-Windows.12
באופן רשמי הוא ממוקם כך:
- מותאם לחומרה ולקלט העדכניים ביותר
- DPI גבוה
- אנימציה חלקה
- חלק מ-Windows App SDK
לכן הוא מתאים לפרויקטים כמו:
- מוצר חדש ייעודי ל-Windows
- הרושם או החוויה של ה-UI עצמם חשובים
- רוצים לנצל את Fluent בטבעיות
- רוצים להתקרב למצב הנוכחי של Windows 11
- רוצים להניח API חלונות חדש וחוויית Windows עדכנית
פרויקט שיש בו סיבה אמיתית לבחור ב-WinUI הוא לרוב לא פרויקט של “המראה חדש”, אלא של “רוצים לשלב את חוויית ה-Windows הנוכחית במוצר”.
flowchart TB
accTitle: איך מזהים סיבה אמיתית לבחור ב-WinUI
accDescr: תרשים שמראה שפרויקט עם סיבה אמיתית לבחור ב-WinUI הוא לא "המראה חדש" אלא "רוצים לשלב את חוויית ה-Windows הנוכחית במוצר" — מוצר חדש ייעודי ל-Windows שבו הרושם של ה-UI חשוב.
y1["פרויקט עם סיבה אמיתית ל-WinUI"] --> y2["לא 'המראה חדש'"]
y2 --> y3["אלא 'חוויית Windows הנוכחית במוצר'"]
y3 -.-> y4["מוצר חדש ייעודי ל-Windows, הרושם חשוב"]
איור 12: הסיבה האמיתית לבחור ב-WinUI היא לא “חדש” אלא “לשלב את חוויית Windows הנוכחית”.
מצד שני, יש גם נקודות זהירות.
5.3.1 WinUI הוא לא “סתם WPF חדש”
מכיוון שהוא משתמש ב-XAML הוא נראה קרוב, אבל —
- ה-API הבסיסי
- סט הפקדים
- מבנה הפרויקט
- הגישה ל-deploy / packaging
- היחס ל-Windows App SDK
שונים.
כלומר, קצת מסוכן לחשוב עליו כתחליף קל ל-WPF.
flowchart TB
accTitle: WinUI אינו סתם WPF חדש
accDescr: תרשים שמראה שהשימוש המשותף ב-XAML גורם ל-WinUI להיראות קרוב ל-WPF, אך ה-API הבסיסי, הפקדים, מבנה הפרויקט, ה-packaging והיחס ל-Windows App SDK שונים, ומסוכן לראות בו תחליף קל.
u1["שימוש משותף ב-XAML"] --> u2["אבל הרבה שונה"]
u2 --> u3["API בסיסי ופקדים"]
u2 --> u4["מבנה ו-packaging"]
u2 --> u5["היחס ל-SDK"]
u5 -.-> u6["מסוכן לראות בו תחליף קל"]
איור 13: למרות ה-XAML המשותף, WinUI אינו תחליף קל ל-WPF.
5.3.2 בבחירת WinUI, נושא ה-deployment קופץ קדימה
לאפליקציית WinUI 3, packaged הוא ברירת המחדל. מצד שני, Windows App SDK עצמו מטפל גם ב-packaged וגם ב-unpackaged.13142
כאן חשוב להחליט מוקדם על:
- איך מפיצים
- איך מכניסים את ה-runtime
- האם דרוש package identity
- הפצה פנים-ארגונית, Store, MSIX, או מסלול EXE / MSI קיים
אבל “להחליט מוקדם” בלבד לא אומר מה בדיוק לבדוק, אז הנה תוכן הבדיקה.
קודם כול, יש שני צירים לקבוע.1315
- packaging: האם לאפליקציה יש package identity
- runtime: להשתמש ב-Windows App SDK כ-framework-dependent, או לצרף אותו כ-self-contained
flowchart TB
accTitle: שני הצירים שקובעים קודם
accDescr: תרשים שמראה שבתכנון ה-deployment של WinUI קובעים קודם שני צירים — ציר ה-packaging, האם לאפליקציה package identity, וציר ה-runtime, האם Windows App SDK כ-framework-dependent או self-contained.
h1["תכנון ה-deployment"] --> h2["ציר ה-packaging"]
h1 --> h3["ציר ה-runtime"]
h2 -.-> h4["האם יש package identity"]
h3 -.-> h5["framework-dependent או self-contained"]
איור 14: בתכנון ה-deployment קובעים קודם שני צירים — packaging ו-runtime.
יש שלוש אפשרויות בצד ה-packaging.13
| מודל | package identity | מתקין | מתאים ל- |
|---|---|---|---|
| packaged (MSIX) | יש | MSIX מחליף את המתקין | פיתוח חדש, פרסום ב-Store, הפצה ארגונית כמו Intune |
| packaged שמצביע על מיקום חיצוני (sparse package) | יש | משתמשים במתקין הקיים כמות שהוא | Win32 / WPF / WinForms קיימים עם מתקין עצמאי |
| unpackaged | אין | MSI / EXE / xcopy | כלי פנימי, Win32 מסורתי בהפצה רחבה |
אחר כך, קובעים אם דרוש package identity מצד הפיצ’רים. פיצ’רים שרשמית מוגדר עבורם “לא עובד בלי package identity” הם, לדוגמה, אלה:13
- background task
- התראות push (WNS)
- share target
- הרחבת תפריט הקשר של Explorer
- שיוך סוגי קבצים וסכימות URI
- startup task
- App Service
- Windows AI API
סדר הבדיקה הבא מעשי בעבודה בפועל.
- לצאת מהדרישות. האם מתוכננים לשמש פיצ’רים מהרשימה למעלה? אם אפילו אחד, נדרש הצד ה-packaged.
- לבדוק אם אפשר לוותר על המתקין הקיים. אם לא רוצים לוותר, התשובה היא לא מעבר מלא ל-MSIX אלא packaged שמצביע על מיקום חיצוני. פריסת הבינארי הקיימת ומנגנון העדכון נשארים כמות שהם, ומוסיפים רק את ה-identity.13
- לבדוק בזמן ריצה. ניתן לקבוע אם ל-process הרץ יש identity באמצעות
GetCurrentPackageFullName. אם אין identity, מוחזרAPPMODEL_ERROR_NO_PACKAGE. להפך, אם קוראים ל-Windows API ומקבליםE_ILLEGAL_METHOD_CALLאוAPPMODEL_ERROR_NO_PACKAGE, זה סימן שנתקעים בדרישת package identity.13 - לבדוק בצד המכשיר. אפשר לרשום את החבילות המותקנות באמצעות
Get-AppxPackageב-PowerShell. - לבסוף, לקבוע את ה-runtime. אם רוצים להפיץ ב-xcopy או zip — self-contained; אם יוצאים ל-Store — framework-dependent הוא המסלול המוגדר כברירת מחדל.15
גם ב-WinForms / WPF ה-deployment חשוב, אבל ב-WinUI זה נוטה לקפוץ קדימה. לאפליקציית WinUI 3 חדשה packaged הוא ברירת המחדל, ולכן אם לא קובעים כלום, זה עולה אוטומטית על מסלול MSIX.13 זה המקום המעט מסובך בעולם הזה — חשבתם שהחלטתם על UI, אבל בפועל החלטתם על אסטרטגיית deployment.
flowchart TB
accTitle: הליך בדיקת package identity
accDescr: תרשים שמראה חמישה שלבים — לצאת מהדרישות, לבדוק אם אפשר לוותר על המתקין הקיים, לבדוק בזמן ריצה, לבדוק בצד המכשיר, ולבסוף לקבוע את ה-runtime.
s1["1. לצאת מהדרישות"] --> s2["2. לבדוק אם אפשר לוותר על המתקין"]
s2 --> s3["3. לבדוק בזמן ריצה"]
s3 --> s4["4. לבדוק בצד המכשיר"]
s4 --> s5["5. לקבוע את ה-runtime"]
s2 -.-> s6["אם לא רוצים לוותר — packaged למיקום חיצוני"]
s3 -.-> s7["קביעה לפי GetCurrentPackageFullName"]
איור 15: את הצורך ב-package identity בודקים לפי דרישות, מתקין, זמן ריצה ומכשיר.
5.3.3 “לערבב WinUI בהדרגה לתוך WPF / WinForms קיימים” — קודם מנסים
כאן קל שהציפיות מתנפחות. אבל גם ב-FAQ של Microsoft כתוב שברוח הדברים, אלא אם ה-UI framework מוכן לעבור מעבר מלא, לרוב אי אפשר להשתמש ב-WinUI. גם סביב XAML Islands, בעוד התיעוד הרשמי מציג מסלול הטמעה לאפליקציות desktop קיימות, הערות השחרור של Windows App SDK 1.4 אומרות שנכון לעכשיו הבדיקה מתמקדת בעיקר באפליקציות C++, ואין רכיבי wrapper נוחים ל-WPF / WinForms.1011
כלומר,
- “נראה שאפשר מעבר הדרגתי”
- “נראה שאפשר להטמיע בהדרגה”
הם רעיונות מושכים, אבל עדיף לבדוק בקטן קודם, לפני שהופכים אותם לאסטרטגיה הראשית של הפרויקט.
WinUI הוא הבחירה ההגיונית ביותר כאשר —
- מתחילים מחדש
- בונים חוויה כמוצר ייעודי ל-Windows
לעומת זאת, כפתרון קליטה למעבר מלא מ-WPF / WinForms קיימים, דרושים סיבה ובדיקה.
flowchart TB
accTitle: לבדוק לפני שהופכים לאסטרטגיה ראשית
accDescr: תרשים שמראה שהרעיון לערבב WinUI בהדרגה מושך, אך ה-FAQ מניח מעבר מלא, ואין רכיבי wrapper נוחים ל-WPF ו-WinForms, ולכן בודקים בקטן לפני שהופכים את זה לאסטרטגיה הראשית.
v1["רוצים לערבב WinUI בהדרגה"] --> v2["רעיון מושך"]
v2 --> v3["ה-FAQ מניח מעבר מלא"]
v3 --> v4["אין wrapper נוח ל-WPF / WinForms"]
v4 --> v5["בודקים בקטן לפני אסטרטגיה ראשית"]
איור 16: “לערבב WinUI בהדרגה” — בודקים בקטן לפני שזה הופך לאסטרטגיה הראשית.
6. טעויות שיקול דעת נפוצות
6.1 “כי הוא הכי חדש — WinUI”
זה מובן, אבל מסוכן למדי.
עדיף לבחון סיבה לבחירת טכנולוגיה חדשה לפי האם יש ערך שאי אפשר להשיג בלי הטכנולוגיה הזו.
- האם חוויית Windows מודרנית היא ערך המוצר
- רוצים לנצל את Fluent בטבעיות
- זה מוצר חדש
- אפשר לקבל את הנחות ה-deployment / תפעול
אם התשובה כאן “כן”, WinUI אפשרות טובה. לעומת זאת, אם זה רק “נראה שיש לו עתיד”, ההסבר לעלות חלש.
flowchart TB
accTitle: לא "כי הוא חדש" אלא לפי ערך
accDescr: תרשים שמראה שסיבה לבחירת טכנולוגיה חדשה צריכה להיבחן לפי ערך שאי אפשר להשיג בלעדיה, ואם התשובה כן WinUI אפשרות טובה, ואם רק "נראה שיש עתיד" ההסבר לעלות חלש.
q0["סיבה לבחירת טכנולוגיה חדשה"] --> q1{"יש ערך שלא ניתן בלעדיה"}
q1 -->|"כן"| q2["WinUI אפשרות טובה"]
q1 -->|"רק 'נראה שיש עתיד'"| q3["ההסבר לעלות חלש"]
איור 17: לא “כי הוא הכי חדש” — בוחרים לפי ערך שאי אפשר להשיג בלי הטכנולוגיה.
6.2 “רוצים Windows App SDK, אז חייבים WinUI”
קל לטעות כאן, אבל זה לא נכון.
את Windows App SDK אפשר להוסיף גם ל-WPF / WinForms קיימים. גם ב-FAQ הרשמי מוסבר שאפליקציות WPF / MFC / WinForms יכולות להשתמש ב-API-ים של Windows App SDK שאינם קשורים ל-WinUI.1089
לדוגמה, פיצ’רים כמו
- App Lifecycle
- Windowing
- Toast Notifications
אפשר לפעמים לשלב תוך שמירה על ה-UI הנוכחי.10
6.3 “WPF / WinForms כבר גמורים”
גם כאן עדיף שלא לפסול בקלות.
גם WinForms וגם WPF ממשיכים לקבל תיעוד ומסלולי הגירה על .NET הנוכחי, ומטופלים רשמית כ-UI פעיל של Windows desktop.34
כמדד לתחזוקה ארוכת טווח, האם ממשיכים להיכנס פיצ’רים חדשים הוא אינדיקטור ברור יותר מ”האם התיעוד עדיין קיים”. מנקודת מבט זו, המצב של שלושתם נראה כך:
| פעילות אחרונה | איך לקרוא | |
|---|---|---|
| WPF | ב-.NET 9 נוסף ערכת נושא Fluent ל-Windows 11, ואפשר להחליף light / dark / system דרך property בשם ThemeMode. יש גם תמיכה בצבע ההדגשה (accent color) של Windows16 |
הנימוק “המראה ישן אז WinUI” נחלש לעומת קודם |
| WinForms | ב-.NET 9 נכנסה תמיכה זמנית ב-dark mode, שאפשר להחליף דרך Application.SetColorMode. עם זאת, זהו פיצ’ר ניסיוני, ותמיכה רשמית מתוכננת ל-.NET 10. גם ה-API-ים לתמיכה אסינכרונית התרבו17 |
נכנסים פיצ’רים חדשים, אבל מעורבים בהם כאלה עם דגל ניסיוני |
| WinUI / Windows App SDK | ממשיך להתעדכן במחזור שחרור עצמאי, נפרד מ-.NET18 | העדכונים פעילים, אבל מכיוון שצריך לעקוב אחריהם בנפרד מגרסת .NET, נוסף פריט אחד לתוכנית התחזוקה |
כלומר, מנקודת מבט של תחזוקה ארוכת טווח, אפשר לקרוא את זה כך:
- WPF ו-WinForms אינם “קפואים ונטושים” — הם מקבלים פיצ’רים בכל שחרור שנתי של .NET. עם זאת, לחלק מהפיצ’רים המרכזיים של WinForms יש שלב ניסיוני, אז צריך לבדוק את תזמון האימוץ.
- בבחירת WinUI, מנהלים בנפרד את תאריך התמיכה של .NET ואת תאריך התמיכה של Windows App SDK. בפרויקטים ארוכי טווח, זה משפיע בלי רעש.
- לא משנה מה בוחרים, אין ערובה ל”עובד ללא שינויים גם בעוד 10 שנים”, אז עדיף לקבוע מראש עד איזו גרסה עוקבים.
flowchart TB
accTitle: איך קוראים תחזוקה ארוכת טווח
accDescr: תרשים שמראה ש-WPF ו-WinForms מקבלים פיצ'רים עם כל שחרור שנתי של .NET, ושבבחירת WinUI מנהלים בנפרד את תאריכי התמיכה של .NET ושל Windows App SDK, ולכן קובעים מראש עד איזו גרסה עוקבים.
m1["WPF / WinForms"] --> m2["פיצ'רים נכנסים עם שחרור .NET"]
m3["WinUI"] --> m4["מנהלים בנפרד תאריכי תמיכה SDK"]
m2 --> m5["קובעים מראש עד איזו גרסה עוקבים"]
m4 --> m5
איור 18: בתחזוקה ארוכת טווח בודקים מה מוביל את העדכונים, וקובעים מראש עד לאן עוקבים.
במיוחד ביישומים עסקיים, לרוב
- קוד קיים
- פקדי צד שלישי
- מספר המסכים
- דוחות והדפסה
- חיבור למכשירים
- תהליך deployment
שוקלים יותר מחדשנות ה-UI framework.
6.4 “אם כבר, rewrite מלא”
rewrite מלא קרוב יותר להחלטה עסקית מאשר לבחירה טכנולוגית.
אם יש אפליקציה קיימת, הדברים שכדאי לבדוק ראשונים הם אלה:
- מה באמת מטריד
- האם זו בעיית UI, או בעיית ארכיטקטורה
- האם ה-DLL / COM / OCX התלויים, הדוחות וה-deployment הם באמת הנטל האמיתי
- האם אפשר לפתור את הבעיה בלי לשנות את כל ה-UI
rewrite של UI מרשים, אבל גם העלות שלו מרשימה. ומעל לכך, גם אם המראה מתחדש, המורכבות הסובבת נשארת לרוב כמות שהיא.
flowchart TB
accTitle: ארבע שאלות לפני rewrite מלא
accDescr: תרשים שמראה ש-rewrite מלא קרוב להחלטה עסקית, ולכן בודקים קודם מה באמת מטריד, האם זו בעיית UI או ארכיטקטורה, האם התלות וה-deployment הם הנטל האמיתי, והאם אפשר לפתור בלי לשנות את כל ה-UI.
r1["1. מה באמת מטריד"] --> r2["2. UI או ארכיטקטורה"]
r2 --> r3["3. תלות ו-deployment — הנטל האמיתי?"]
r3 --> r4["4. אפשר לפתור בלי לשנות UI?"]
r4 -.-> r5["גם ל-rewrite עלות מרשימה"]
איור 19: לפני rewrite מלא, בודקים בארבע שאלות מה באמת מטריד.
6.5 “אחר כך אפשר לפתור עם XAML Islands”
אפשר להבין את הציפייה הזו. אבל בטוח יותר לא להתייחס אליה כסירת הצלה מלכתחילה.1011
לפני מעבר הדרגתי, כדאי לבדוק בקטן קודם:
- אילו פקדים רוצים להטמיע
- מה קורה עם focus, קלט, DPI ותמה
- האם תצורת ה-host הזו יציבה בפועל
flowchart TB
accTitle: בודקים XAML Islands בקטן מראש
accDescr: תרשים שמראה שבמעבר הדרגתי בודקים מראש בקטן אילו פקדים רוצים להטמיע, מה קורה עם focus, קלט, DPI ותמה, והאם תצורת ה-host יציבה, ולא מתייחסים לזה כסירת הצלה מלכתחילה.
p0["הציפייה 'אחר כך יסתדר'"] --> p1["אילו פקדים להטמיע"]
p0 --> p2["focus, קלט, DPI, תמה"]
p0 --> p3["האם תצורת ה-host יציבה"]
p1 --> p4["בודקים בקטן מראש"]
p2 --> p4
p3 --> p4
איור 20: את XAML Islands בודקים בקטן מראש, ולא מתייחסים אליו כסירת הצלה.
7. נקודת המבט כשמניחים אפליקציה קיימת
כאן, הקיים חשוב יותר מהחדש.
7.1 אם יש WinForms קיים
קודם, לפני שקופצים ישר ל-WinUI, בודקים את אלה:
- אפשר להתקרב ל-.NET הנוכחי
- דרוש מעבר ל-64bit
- אפשר לארגן async / await, טיפול בחריגות, הגדרות ולוגים
- אפשר להעלות תחזוקתיות דרך פיצול מסכים או המרה ל-UserControl
- אפשר להוסיף רק את פיצ’רי Windows הדרושים דרך Windows App SDK
לא נדיר שמה שנראה כבעיית WinForms הוא בפועל רק
- ערבוב בין המסך ללוגיקה
- גבולות thread רשלניים
- אחריות דחוסה של הגדרות / קבצים / COM / DB
במקרה כזה, גם מעבר ל-WinUI רק ישאיר את הבעיה עם שם אחר.
flowchart TB
accTitle: הבעיה נשארת עם שם אחר
accDescr: תרשים שמראה שמה שנראה כבעיית WinForms הוא לרוב בעיית מבנה — ערבוב מסך ולוגיקה, גבולות thread רשלניים, אחריות דחוסה — ובמקרה כזה גם מעבר ל-WinUI ישאיר את הבעיה עם שם אחר.
e1["נראה כבעיית WinForms"] --> e2["בפועל בעיית מבנה"]
e2 --> e3["ערבוב מסך ולוגיקה"]
e2 --> e4["גבולות thread רשלניים"]
e2 --> e5["אחריות דחוסה"]
e4 --> e6["מעבר ל-WinUI — נשאר עם שם אחר"]
איור 21: בעיה שנראית כבעיית UI היא לרוב בעיית מבנה, ונשארת גם אחרי החלפת framework.
7.2 אם יש WPF קיים
קל לנצל את הקוד הקיים ב-WPF.
- נכסי XAML
- Binding
- Style / Template
- Command
- MVVM
הסיבה לזרוק את אלה צריכה להיות ברורה למדי.
לדוגמה, אם —
- רוצים לחדש לגמרי את ה-UI של המוצר
- רוצים ש-Fluent יהיה הציר המרכזי
- מוציאים מודול חדש כמוצר נפרד
- רוצים להתקרב לחוויה חדשה כמוצר ייעודי ל-Windows
זו סיבה לשקול WinUI. אבל רק “כי WPF ישן” — זה חלש.
7.3 מה שבאמת כבד הוא לרוב לא ה-UI
בעבודה בפועל, מה שקשה לרוב מפתיע הוא אלה:
- ActiveX / OCX
- COM interop
- דוחות עצמאיים
- הדפסה
- שילוב עם Excel / Office
- DLL נייטיבי
- קונפליקט 32bit / 64bit
- מתקין, הרשאות, עדכון, חתימה
אם מזלזלים כאן, גם ניקוי ה-UI בלבד לא יקל על הפרויקט כולו.
לכן, במעבר אפליקציה קיימת, עדיף לא רק להסתכל על ה-UI framework, אלא לעשות מלאי לכל גבול תלות.
flowchart TB
accTitle: עושים מלאי לכל גבול תלות
accDescr: תרשים שמראה שבעבודה בפועל מה שכבד הוא לרוב ActiveX או COM, דוחות והדפסה, DLL נייטיבי, מתקין ועדכון — לא ה-UI — ולכן עושים קודם מלאי לכל גבול תלות.
d1["ActiveX / COM interop"] --> d4["מה שכבד באמת — לא ה-UI"]
d2["דוחות, הדפסה, שילוב Office"] --> d4
d3["מתקין, הרשאות, עדכון, חתימה"] --> d4
d4 --> d5["קודם עושים מלאי לכל גבול תלות"]
d5 -.-> d6["ניקוי ה-UI בלבד לא מקל"]
איור 22: מה שבאמת כבד במעבר הוא לרוב תלות מחוץ ל-UI, ולכן עושים מלאי קודם.
8. חמש השאלות האחרונות למי שמתלבט
אם עדיין מתלבטים, עונים על חמש השאלות האלה בסדר.
8.1 האם הקוד הקיים גדול
- גדול → משמרים בעיקרון את אותו קו
- קטן / אין → עוברים לבחירה חדשה
8.2 האם “חוויית Windows מודרנית” הכרחית לאפליקציה הזו
- הכרחית → WinUI אפשרות טובה
- לא כל כך → בודקים אם WPF / WinForms מספיקים
8.3 האם המסך מבוסס טפסים סטנדרטיים, או שצריך גמישות בסגנון XAML
- מבוסס טפסים סטנדרטיים → WinForms
- style / template / Binding / MVVM חשובים → WPF
8.4 רוצים חידוש מלא של ה-UI, או הוספת פיצ’רי Windows
- חידוש מלא של ה-UI → שוקלים WinUI
- רק הוספת פיצ’רים → בודקים קודם WPF / WinForms הנוכחיים + Windows App SDK
8.5 האם אפשר להסביר מראש איך מטפלים ב-deployment / עדכון / תפעול
- עדיין מעורפל → ב-WinUI ממלאים מוקדם את פרטי ה-packaging / deployment
- רוצים להסתמך חזק על התפעול הקיים → לרוב WPF / WinForms יוצרים פחות חיכוך
flowchart TB
accTitle: זרימת חמש השאלות האחרונות
accDescr: תרשים שמראה שעונים בסדר על האם הקוד הקיים גדול, האם חוויה מודרנית הכרחית, האם המסך מבוסס טפסים או שצריך גמישות, וכך מצמצמים את האפשרויות.
f1{"האם הקוד הקיים גדול"} -->|"גדול"| f2["משמרים את אותו קו"]
f1 -->|"קטן / אין"| f3{"חוויה מודרנית הכרחית"}
f3 -->|"הכרחית"| f4["WinUI אפשרות טובה"]
f3 -->|"לא כל כך"| f5{"מבוסס טפסים סטנדרטיים"}
f5 -->|"כן"| f6["WinForms"]
f5 -->|"גמישות חשובה"| f7["WPF"]
f2 -.-> f8["אם רק פיצ'רים — קודם SDK"]
f4 -.-> f9["ממלאים מוקדם packaging ו-deployment"]
איור 23: עונים בסדר על קוד קיים, חוויה ואופי המסך, ומצמצמים את האפשרויות.
חמש השאלות האלה מצמצמות משמעותית. לסיכום גס:
- טופס פנימי שבונים מהר → WinForms
- יישום עסקי ל-Windows שגדל לאורך זמן → WPF
- UI מוצרי מודרני חדש ל-Windows → WinUI
- מנצלים את הקיים ומשלבים רק פיצ’רי Windows → ה-framework הנוכחי + Windows App SDK
9. סיכום
הבחירה בין WinForms, WPF ו-WinUI היא לא משחק של לסדר לפי חדשנות ולקחת את הימני ביותר.
ארבעת הדברים שכדאי לבדוק ראשונים:
- איפה נמצא הקוד הקיים
- האם המסך מבוסס טפסים, או מבוסס גמישות UI
- האם UI מודרני ואופייני ל-Windows הוא דרישת מוצר
- איך מנהלים deployment / עדכון / תפעול
אם רואים את ארבעתם, המדיניות כמעט נקבעת.
flowchart TB
accTitle: ארבע השאלות המסכמות
accDescr: תרשים שמראה שאם רואים את הקוד הקיים, אופי המסך, דרישת UI מודרני, ו-deployment ותפעול, המדיניות כמעט נקבעת.
n1["קוד קיים"] --> n5["המדיניות כמעט נקבעת"]
n2["אופי המסך"] --> n5
n3["דרישת UI מודרני"] --> n5
n4["deployment ותפעול"] --> n5
איור 24: אם רואים את ארבע השאלות, מדיניות בחירת ה-framework כמעט נקבעת.
- אם יש WinForms קיים גדול — קודם המשך עם WinForms
- אם יש WPF קיים גדול — קודם המשך עם WPF
- בפיתוח חדש מבוסס טפסים סטנדרטיים — WinForms
- בפיתוח חדש של יישום עסקי בינוני-גדול ל-Windows — WPF
- בפיתוח חדש שבו חוויית Windows מודרנית היא עצמה הדרישה — WinUI
- אם רוצים רק Windows App SDK — לא עוברים ישר לגמרי ל-WinUI
שלושת הדברים שהכי כדאי להימנע מהם:
- לזרוק כי זה ישן
- לבחור כי זה חדש
- להתחיל מתוך “יסתדר בהמשך”
Windows desktop הוא עולם שבו קוד קיים, deployment, תפעול ותלויות שוקלים יותר מהמראה. לכן, גם בבחירה עצמה, להסתכל על מעט חיכוך ולא על ברק, זה לרוב הדרך שמנצחת.
10. מקורות
-
Microsoft Learn, “WinUI 3 - Windows apps” / Microsoft Learn, “Modernize your desktop apps for Windows” ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7
-
Microsoft Learn, “Windows フォームとは - Windows Forms” ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, “Windows Presentation Foundation とは - WPF” ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, “What is Windows Forms Designer?” ↩ ↩2
-
Microsoft Learn, “Data binding overview - WPF” ↩ ↩2 ↩3
-
Microsoft Learn, “Commanding Overview - WPF” ↩ ↩2 ↩3
-
Microsoft Learn, “WPF アプリでWindows App SDKを使用する” ↩ ↩2 ↩3
-
Microsoft Learn, “Use the Windows App SDK in a Windows Forms (WinForms) app” ↩ ↩2 ↩3
-
Microsoft Learn, “Windows 開発者向け FAQ” ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9
-
Microsoft Learn, “Windows App SDK 1.4 release notes” / Microsoft Learn, “Windows App SDK” ↩ ↩2 ↩3
-
Microsoft Learn, “Windows data binding and MVVM” ↩
-
Microsoft Learn, “Packaging overview - Windows apps” / Microsoft Learn, “Grant package identity by packaging with external location” ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7
-
Microsoft Learn, “Quick start: Set up your environment and create a WinUI 3 project” ↩
-
Microsoft Learn, “Package and deploy Windows apps overview” ↩ ↩2
-
Microsoft Learn, “What’s new in WPF for .NET 9” ↩
-
Microsoft Learn, “What’s new in WinForms for .NET 9” ↩
-
Microsoft Learn, “Windows App SDK release channels” ↩
מאמרים קשורים
מאמרים עדכניים עם אותן תגיות, להעמקה בנושאים קרובים.
למה להכניס Generic Host ו-BackgroundService לאפליקציית desktop ב-.NET
בכלי Windows ובאפליקציות long-running, איך להשתמש ב-Generic Host וב-BackgroundService כדי לרכז הפעלה, עיבוד תקופתי, shutdown, לוג, הגדרות...
סיום התמיכה ב-printer drivers של Windows — איך אפליקציות עסקיות מתכוננות להדפסת דוחות ותוויות
Microsoft מפסיקה בהדרגה printer drivers מסוג v3/v4. מה Windows protected print mode מסיר, ואיך עושים inventory ומכינים הדפסת דוחות ותוויו...
מה Not Responding באמת אומר — איך Windows מחליט שיש hang, ואיך לתכנן אפליקציות שלא נתקעות
Windows מסמן window כ-Not Responding אחרי 5 שניות בלי שליפת message ומציג ghost window: השיפוט, סיבות ה-hang, תכנון ה-UI thread, והחקירה.
איך clipboard ו-drag-and-drop עובדים — טיפול נכון ב-OLE data transfer באפליקציות עסקיות
למה הדבקת Excel מתפרקת ולמה paste נכשל אחרי סגירת המקור: clipboard formats, delayed rendering, OLE drag-and-drop, ומדיניות clipboard hist...
async/await וה-UI thread ב-WPF וב-WinForms
ב-WPF וב-WinForms, לאן חוזר הקוד אחרי await, מתי להשתמש ב-Dispatcher או Invoke, מה ConfigureAwait(false) באמת עושה, ולמה .Result ו-.Wait(...
נושאים קשורים
העמודים האלה ממקמים את הנושא בהקשר רחב יותר של שירותים והחלטות.
נושאים טכניים ב-Windows
שער לנושאי פיתוח Windows, חקירת תקלות וניצול נכסים קיימים.
תהליכון ה-UI וטיימרים
תהליכון ה-UI של WPF / WinForms, זרימות אסינכרוניות, Dispatcher ותכנון טיימרים.
שירותים הקשורים לנושא הזה
המאמר קשור ישירות לשירותים הבאים.
פיתוח יישומי Windows
הבחירה בין WinForms, WPF ו-WinUI משפיעה ישירות על פיתוח חדש של אפליקציות desktop ל-Windows ועל איך ממשיכים לתחזק אפליקציות קיימות.
ייעוץ טכני וסקירת תכנון
מתאים לשלב שבו בודקים איזו בחירה יוצרת הכי פחות חיכוך, כולל קוד קיים, Windows App SDK, תכנון deployment, גמישות UI ותרבות MVVM.
שאלות נפוצות
שאלות נפוצות בפניות בנושא המאמר.
- מה ההבדל בין WinUI 3 ל-WPF?
- שניהם משתמשים ב-XAML, אבל WinUI הוא לא 'סתם WPF חדש'. ה-API הבסיסי, סט הפקדים, מבנה הפרויקט, הגישה ל-deploy/packaging, והיחס ל-Windows App SDK — כולם שונים. WPF הוא UI framework ליישומים עסקיים בינוניים עד גדולים, עם ציור וקטורי שאינו תלוי ברזולוציה, data binding, style/template ו-command. WinUI, כחלק מ-Windows App SDK, הוא UI framework מודרני שמניח Fluent, DPI גבוה וחוויית Windows עדכנית. מסוכן לראות בו תחליף קל ל-WPF.
- בפיתוח חדש, במה לבחור מבין WinForms, WPF ו-WinUI?
- זה תלוי באופי המסכים ובדרישות המוצר. אם רוצים לבנות מהר כלי פנימי קטן עד בינוני שמבוסס על פקדים סטנדרטיים וטפסי קלט, WinForms עדיין חזק. אם זה יישום עסקי בינוני עד גדול עם הרבה מסכים, ורוצים להשתמש כראוי ב-data binding, style, template ו-MVVM, WPF לרוב הבחירה הבטוחה ביותר. למוצר חדש ייעודי ל-Windows שבו Fluent וחוויית Windows מודרנית הם חלק מערך המוצר, WinUI אפשרות טובה. כשיש הרבה קוד קיים, קודם בודקים אם אפשר להמשיך באותו קו.
- האם WPF ו-WinForms כבר מיושנים?
- עדיף לא לפסול אותם בקלות. גם WinForms וגם WPF ממשיכים לקבל תיעוד ומסלולי הגירה על .NET הנוכחי, ומטופלים רשמית כ-UI פעיל של Windows desktop. במיוחד ביישומים עסקיים, קוד קיים, פקדי צד שלישי, דוחות והדפסה, חיבור למכשירים ותהליך deployment שוקלים לרוב יותר מחדשנות של ה-UI framework. גם בפיתוח חדש, לא נדיר ש-WinForms או WPF הם הבחירה עם הכי פחות חיכוך.
- צריך לעבור ל-WinUI כדי להשתמש בפיצ'רים העדכניים של Windows?
- לא. Windows App SDK ו-WinUI אינם אותו דבר — WinUI הוא חלק ה-UI framework בתוך Windows App SDK. את Windows App SDK עצמו אפשר להוסיף גם לאפליקציות קיימות של WPF / WinForms / Win32, ופיצ'רים כמו App Lifecycle, Windowing ו-Toast Notifications אפשר לפעמים לשלב בלי להחליף את ה-UI. כלומר אפשר להישאר עם WPF / WinForms הקיימים ולשלב רק את פיצ'רי Windows שצריך, ומעבר מלא של ה-UI אינו חובה.