שאלה:
אין לי ידע רחב ב C# אך לעומת זאת יש ידע ב MFC ו C++.
אני עומד להתחיל לבנות אפליקציה לחבר בעל חברת השמה.
אני יכול לבנות לו את זה ב MFC או ב WINDOWS FORMS אבל קראתי הרבה על WPF ואני שוקל אם כבר, להתמקצע בזה למטרת בניית אפליקציות מהסוג הנ"ל. אין לי בעיה להעמיק את הידע ב C#(לא מעוניין ב VB).
ראיתי ש WPF מספק UI עשיר מאוד וזה נראה באמת הדור הבא של UI.
מה דעתכם ? האם מישהו כבר בנה אפליקצייה עם הטכנולוגיה הזאת ?
אשמח לשמוע התרשמויות מבעלי נסיון.
תשובה:
WPF זה הדור הבא של אפליקציות שולחניות.
הוא מאפשר לבנות אפליקציות גרפיות ברמה שלא הכרנו בעבר.
היתרונות הגדולים שלו: (לפי דעתי ובלי סדר ספציפי)
1. אפליקציות WPF מתאימות את עצמן לרזולוצית המשתמש, ה-DPI של המסך שלו ולשטח המסך הזמין.
שמעצבים תמיד מעצבים ב-1 יחידות WPF סטנדרטיות ולא בפיסקלים או משהו כזה.
ככה שהאפליקציות נראות אותו דבר בלי קשר לרזולוציה והן יודעות לסדר את עצמן מחדש מצויין לפי כמה שטח מסך יש להן.
למשל נביט על יכולות ה-Resizing של WPF.
נגיד וציירנו כפתור שלוקח את כל השטח בתא שגדולה 100 (יחסי) על 100 (יחסי).
זה ה-XAML שנקבל:
<Window x:Class="WPFTesting.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window2" Height="300" Width="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="100*" />
<RowDefinition Height="162*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100*" />
<ColumnDefinition Width="178*" />
</Grid.ColumnDefinitions>
<Button Name="button1">Button</Button>
</Grid>
</Window>
האפליקציה שלנו תיראה כך שנתחיל אותה בגודל מסויים שקבענו מראש:
נוכל גם להגדיל את החלון והכפתור ימשיך לתפוס גודל יחסי.
או להקטין את החלון והכפתור עדיין יתפוס גודל יחסי.
אפשר לראות ביחס לכללים שהגדרנו כחלק מעיצוב הטבלה שלנו והעובדה שהכפתור תופס את כל התא בטבלה, הוא מסוגל להגיע לשנות את הגודל שלו באופן דינמי.
בכלל WPF יודע לתת התייחסות מצויינת לגודל הסופי של אלמנט על המסך דרך פרדיגמת: Measure Twice, Cut Once. למעשה, WPF שואל את האלמנטים שלו "מה הגודל שאתם חושבים שתצטרכו?" ובנפרד מודיע לכל אלמנט "זה הגודל הסופי שקיבלתם לפי מערכת ה-Layout המאוד מתוחכמת שלי".
יש עוד המון אפשרויות Layout כאלו שיודעות להתאים את התוכן לגודל המסך הזמין, הרזולוציה וה-DPI של המסך.
2. מודל ה-Content. בכל מקום שהיינו רגילים ב-Winforms שמבקשים מאתנו String לתצוגה, עכשיו מבקשים מאתנו UIElement.
כלומר, אם פעם היה Button.Text ב-Winforms, אז ב-WPF יש לנו Button.Content.
ככה שלמעשה אפשר להכניס מחדש על אלמנט גרפי לתוך אלמנטים גרפיים אחרים. מה שב-Winforms ובטכנולוגיות אחרות מהדור שלו, בלתי אפשרי או דורש המון המון המון עבודה עם ציור ידני.
למשל, ניקח באמת את דוגמת הכפתור אם נרצה להכניס לתוכו ווידאו מהאינטרנט נוכל באמצעות ה-XAML הבא.
<Window x:Class="WPFTesting.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window2" Height="300" Width="300">
<Grid>
<Button Name="button1" Margin="35,30,43,40">
<Button.Content>
<MediaElement Source="http://silverlight.net/quickstarts/silverlight10/thebutterflyandthebear.wmv" />
</Button.Content>
</Button>
</Grid>
</Window>
שימו לב שיש בתוך Button.Content את אלמנט ה-MediaElement שמצביע לקובץ WMV באינטרנט. (אומנם עדיף במציאות לעבוד רק מול קבצים לוקאליים, אבל זה רק הדגמה ליכולות של WPF).
אם נריץ את האפליקציה נקבל את הכפתור הבא:
מודל כזה שמאפשר לנו למעשה לקסטם הכל-מהכל בקשר לתצוגה של כל פקד נותן המון כוח גרפי בידיים של המעצב.
3. ההפרדה בין "עיצוב" ל-"פונקציונליות" הרבה יותר ברורה באמצעות קבצי XAML.
אפשר אפילו באמת להגיע למצב שמעצב עובד על איך מסך נראה ואיפה הוא מציג מידע, שהתוכניתן רק דואג לחשוף למעצב את המידע והאירועים המתאימים.
המעצב שהוא יושב בתוכנה היעודית שלו Expression Blend יכול לקשר כפתור ל-Command שהמתכנת חשף לו מראש ולבצע DataBinding בצורה גרפית על Net Classes.
בואו נציג תרחיש שבו אנחנו בונים מערכת CRUD בסיסית לפרות ובעזרתו נדגים גם את Commands וגם את Databinding ואת ההפרדה המצויינת שהם עוזרים להשיג בין תכנות לבין עיצוב מסך.
נתחיל מדוגמה על Commands.
המתכנת יצור Commands, המעצב ישתמש בהן, והמתכנת בכלל לא יודע מה הולך ב-GUI.
המתכנת בא ויצר פקודה חדשה.
public partial class Window2 : Window
{
public static RoutedCommand InsertNewCowCommand =
new RoutedCommand("InsertNewCowCommand", typeof(Window2));
public Window2()
{
InitializeComponent();
}
}
כבר בשלב הזה, המעצב יכול להרים את הפקודה, בלי שום טיפול מהמתכנת.
אבל בכל זאת המתכנת שלנו מחליט שהוא רוצה בשלב הזה לגשת לטופס ולקחת ממנו את הפרה שהכניס המשתמש למסד נתונים.
public partial class Window2 : Window
{
public static RoutedCommand InsertNewCowCommand =
new RoutedCommand("InsertNewCowCommand", typeof(Window2));
public Window2()
{
InitializeComponent();
CommandManager.RegisterClassCommandBinding(this.GetType(),
new CommandBinding(InsertNewCowCommand, InsertNewCowCommandExcuted));
}
private void InsertNewCowCommandExcuted(object sender, ExecutedRoutedEventArgs e)
{
// Insert Cow Into Database, designer doesn't know this
MessageBox.Show("Cow has been inserted to DB");
}
}
הגיע המצב שלנו, פתח את Expression Blend ואפילו צייר כפתור.
עכשיו המעצב מפרט איזה פקודה מעלה האירוע ברירת מחדל של הכפתור (שהוא Button.Click).
וכשנריץ את האפליקציה שלנו נוכל לראות שלחיצה כל הכפתור באמת עולה הפקודה שלנו.
ככה שהמתכנת יטפל בכל העיבוד והלוגיקה העסקית שהפקודה תעלה, והמעצב רק צריך לדעת לעלות את הפקודה באופן יחסי ל-GUI שהוא בונה.
הטיפול ב-DataBinding עובד בצורה דומה.
המתכנת יבנה את המחלקה שלו - Cow.
המעצב ידאג לחבר את המאפיינים של המחלקה לחלקים שונים בטופס.
המתכנת בא וכתב את המחלקה שלו.
namespace BL
{
public class Cow
{
public Cow()
{
}
public Cow(string Name)
{
this.Name = Name;
}
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
}
}
סה"כ אין פה הרבה - יש מחלקה עם מאפיין (גם באנגלית: Property) בשם Name שמחזיק את השם של הפרה שלנו ושני קונסטרקטורים.
המעצב יגיע ל-Expression Blend ויבחר שהוא רוצה לעשות DataBinding ל-Cow.Name ישר לתוך TextBox שהוא שם על הטופס.
אז דבר ראשון הוא יוסיף TextBox.
ילחץ על הכפתור הלבן הקטן מצד ימין למאפיין Text ויבחר DataBinding.
יוסיף Data Source חדש לטופס שמצביע על Cow.
ויעשה Drag & Drop ל-Name ישר לתוך ה-TextBox.
יבחר שהוא רוצה לבצע DataBinding ל-Text.
ועכשיו כל מה שנותר זה לדאוג שהתכנת דואג לתת לטופס Data Source כלשהו.
public partial class Window2 : Window
{
public Window2()
{
this.DataContext = new Cow("עדנה");
}
}
ומולנו נקבל את הטופס הבא:
שימו לב להפרדה שקיבלנו באמצעות ה-Databinding של WPF.
המתכנת דואג ליצור מחלקה שתהיה מקור מידע, ולהכניס ולהוציא מידע מאותו מקור מידע.
המעצב דואג מה לעשות עם המידע.
יש כאן הפרדה טוטאלית בין "האופי של המידע וההתנהגות של החלון" לבין "מה עושים עם המידע בתוך החלון".
מודל ה-DataBinding ומודל ה-Commands של WPF יוצר הפרדה מוחלטת בשתי הנקודות הכואבות של תכנות חלונאי עד כה ובאמת מאפשר למעצב לעבוד עצמאית מתוכניתן אחרי שהכינו לו את התשתית.
4. העובדה שעכשיו יש לנו אפשרות לתכנות "דמוי CSS" זה אחד מהפיצ'רים הבאמת חדשניים של WPF?
ככה אפשר להכיל סגנון גרפי על כל האפליקציה בשניות.
(כמובן שיש גם אפשרות לירושה בין ה-Styleים אז זה בכלל יוצא מצויין)
מה-Styleים של WPF גם ניתן לקבוע תוכן ברירת מחדל וציור ברירת מחדל לחלוטין.
למשל, ה-Style ה-WPF הבא ידאג לפרמט סוג וגודל פונט לכפתורים כל האפליקציה. (כאשר הוא יושב בקובץ ה-App.xaml של האפליקציה)
<Style TargetType="{x:Type Button}">
<Setter Property="FontSize" Value="22"/>
<Setter Property="FontFamily" Value="Arial"/>
</Style>
בדוגמה ל-CSS יש לנו שלוש רמות של Style:
1. שמתאים לכל אלמנט גרפי מסוג מסויים ברחבי האפליקציה. זאת הדוגמה שראינו למעלה.
2. שמתאים לכל אלמנט גרפי מסוג מסויים בתוך חלון או Container כלשהו. (ככה אפשר לפרמט רק כפתורים בתוך Panel או Window מסויים)
3. שמתאים רק לאלמנט גרפי ספציפי או שביקש ספציפית שה-Style יפעל עליו.
בניגוד ל-CSS קיבלנו גם פיצ'ר מדהים של ירושה בין Styleים.
למשל בדוגמה הבאה נירש את BaseStyle ונוסיף לו.
<Style TargetType="{x:Type Button}" x:Key="BaseStyle">
<Setter Property="FontSize" Value="22"/>
<Setter Property="FontFamily" Value="Arial"/>
</Style>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource BaseStyle}">
<Setter Property="FontWeight" Value="Bold" />
</Style>
עכשיו כל הכפתורים באפליקציה מקבלים גם את BaseStyle וגם את היורש ממנו.

כמובן שכל העניין הזה עם ה-Styleים הוא אוטומטי 99% דרך Expression Blend ומעצב רק גורר דברים ממקום למקום וקובע מאפיינים כרגיל.
ככה שקיבלנו מן תחליף לירושה של התוכניתן של פקדים בשביל לקבוע ערכי ברירת מחדל והורדנו עוד עבודה מהתוכניתן שזה מגיע לעיצוב גרפי.
עכשיו המעצב יכול לבד דרך הממשק הגרפי הנקי והיפה שלו לכתוב "CSS חלונאי" לכל האפליקציה.
5. אנימציות.
לא היינו יכולים בעבר לעשות אנימציות בחלונות, ועכשיו יש לך מודל שלם שהוא אזרח ממדרגה ראשונה בתוך הפריימוורק.
דבר מצויין.
למשל, אם הייתי רוצה שב-Button Click הכפתור יעשה סיבוב של 360 מעלות תוך 2 שניות ויזוז ימינה, פשוט אי-אפשר לעשות את זה בצורה הגיונית ב-Winforms. זה ייקח לפחות שבוע עבודה ב-Winforms ויראה נורא.
אבל ב-WPF אנימציות הן פיצ'ר משמעותי ודרך Expression Blend ניתן לצייר אותן.
נממש את הדוגמה עם הכפתור שלנו שדיברנו עליה לפני שנייה.
נבחר להוסיף Trigger חדש לטופס שיעבוד על button Click.
נבחר להוסיף Storyboard חדש באירוע הזה.

דרך ה-Designer הגרפי גררתי את הכפתור 100 פיסקלים ימינה וסובבתי אותו, והכל בסימן ה-2 שניות באנימציה.
אפשר בצד שמאל למטה לראות לפי הקו הצהוב שאנחנו בסימן ה-2 שניות לביצוע האנימציה.
אפשר גם לראות שהכפתור קצת על הצד, זה כי קבעתי לו שבסיום ה-2 שניות הוא יהיה ב-359 מעלות סיבוב.
ואם נריץ את האפליקציה נראה במהלך ה-2 שניות את האנימציה הבאה את האנימציה מאוד חלקה הבאה.
כל זה בלי שום התערבות מצידנו כתוכניתנים, בלי שום כתיבת קוד של המעצב והכל באופן אינטגרלי מובנה בשפה.
סה"כ אלו היתרונות הגדולים של WPF לפי דעתי.
כדי לתת קונטרה ליתרונות חשוב להדגיש שמגיעים לרמות הגבוהות של עבודה עם WPF נתקלים במספר מכשולים ועומר כתב עליהם בצורה מצויינת.
קישור: http://www.tapuz.co.il/tapuzforum/main/Viewmsg.asp?forum=831&msgid=112351636