מדריך WPF

מדריך WPF – שימוש ב Routed Events

‏ • Sela

הקדמה

בפרק שעבר למדנו שבWPF החליטו לשפר את מערכת הProperties ולהוסיף Properties בעלי יתרונות חדשים שנקראים Dependency Properties. באותו אופן, גם Events (אירועים) היו זקוקים למקצה שיפורים בWPF, ולEvents מהסוג החדש קוראים Routed Events. אלו אירועים בעלי יתרונות ביחד לאירועים הרגילים בשפת #C. גם פרק זה יהיה בעיקר תיאורטי.

יתרונות Routed Events

הרעיון המרכזי ב Routed Events הוא שכאשר אירוע מופעל, הוא מופעל מספר פעמים, על פקדים נוספים בעץ הפקדים באפליקציה שלנו. לדוגמא, אם יש לנו את מבנה האפליקציה הבא:

<Window x:Class="EventsDemo.MainWindow"
       >="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
       >:x="http://schemas.microsoft.com/winfx/2006/xaml"
       Title="MainWindow"
       Height="350"
       Width="525">
  <StackPanel>
    <Button>
      <Button.Content>
        <StackPanel Orientation="Horizontal">
          <Image Width="100"
                Source="/EventsDemo;component/Images/Koala.jpg"
                Margin="10" />
          <TextBlock Text="text next to image"
                    VerticalAlignment="Center" />
        </StackPanel>
      </Button.Content>
    </Button>
  </StackPanel
>
</
Window
>

באפליקציה זו יש לנו חלון שבתוכו StackPanel ובתוכו כפתור, והכפתור מכיל תמונה וטקסט.

מדריך WPF – שימוש ב Routed Events

נניח שאירועים היו מתנהגים כרגיל, ולא כמו שRouted Events עובדים. ונניח שנרצה להגיב לאירוע ללחיצה עם כפתור ימני של העכבר על הכפתור שלנו, אזי נצטרך להירשם לאירוע MouseRightButtonDown. אבל מה היה קורה אם היינו מבצעים את הלחיצה על התמונה שנמצאת בתוך הכפתור? מי שיקבל את הלחיצה ויפעיל את האירוע הוא אותה תמונה ולא הכפתור! כלומר אם נרצה שיופעל הקוד שלנו בעת לחיצה ימנית על הכפתור (בתוך התמונה ומחוצה לה!), יש להירשם לאירוע גם של הכפתור, גם של התמונה, גם של הפקד TextBlock וגם של ה StackPanel! כמובן שמצב כזה הוא מאוד מסורבל ולא נוח. הקוד הדרוש לרישום לכל האירועים הללו יראה כך:

<Window x:Class="EventsDemo.MainWindow"
       >="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
       >:x="http://schemas.microsoft.com/winfx/2006/xaml"
       Title="MainWindow"
       Height="350"
       Width="525">
  <StackPanel>
    <Button MouseRightButtonDown="Button_MouseRightButtonDown">
      <Button.Content>
        <StackPanel Orientation="Horizontal"
                    MouseRightButtonDown="Button_MouseRightButtonDown">
          <Image Width="100"
                Source="/EventsDemo;component/Images/Koala.jpg"
                Margin="10"
                 MouseRightButtonDown="Button_MouseRightButtonDown" />
          <TextBlock Text="text next to image"
                    VerticalAlignment="Center"
                     MouseRightButtonDown="Button_MouseRightButtonDown" />
        </StackPanel>
      </Button.Content>
    </Button>
  </StackPanel
>
</
Window
>

 

התוספת המרכזית בRouted Events היא שלאחר שהאירוע שלנו מופעל על התמונה, האירוע "מטפס" במעלה עץ הפקדים, מגיע ל StackPanel ומופעל גם עליו, ואז ממשיך במעלה עץ הפקדים, ומופעל על ה Button, ואז תקרא הפונקציה שרשמנו אותה. באופן זה המקום היחיד שנצטרך להירשם אליו הוא הכפתור עצמו, כלומר הקוד הופך להיות קצר והגיוני:

<Window x:Class="EventsDemo.MainWindow"
       >="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
       >:x="http://schemas.microsoft.com/winfx/2006/xaml"
       Title="MainWindow"
       Height="350"
       Width="525">
  <StackPanel>
    <Button MouseRightButtonDown="Button_MouseRightButtonDown">
      <Button.Content>
        <StackPanel Orientation="Horizontal">
          <Image Width="100"
                Source="/EventsDemo;component/Images/Koala.jpg"
                Margin="10" />
          <TextBlock Text="text next to image"
                    VerticalAlignment="Center" />
        </StackPanel>
      </Button.Content>
    </Button>
  </StackPanel
>
</
Window
>

אם נזכור את העובדה שבWPF קל מאוד לשים פקדים בתוך פקדים, מאחר והתכונה Content יכולה להכיל אוסף פקדים אחרים, נבין שיתרון של Routed Events ביחס לאירועים רגילים הוא ממש הכרחי בWPF. מסיבה זו רוב האירועים בWPF הם Routed Events.

 

סוגים שונים של Routed Events

קיימים שלושה סוגים של Routed Events. ההבדל בין הסוגים השונים הוא מה ההתנהגות של האירוע לאחר שהוא הופעל לראשונה.

  1. אירוע מסוג Bubbling – אירוע מסוג זה מתרחש קודם על הפקד שיצר אותו ואז מטפס במעלה עץ הפקדים ופועל שוב ושוב עד שהוא מגיע לשורש העץ, החלון הראשי. בדוגמא הקודמת האירוע MouseRightButtonDown הוא מסוג Bubbling.
  2. אירוע מסוג Tunneling – אירוע מסוג זה מתרחש קודם על שורש העץ, החלון הראשי, ואזי הוא מחלחל במורד העץ, ופועל שוב ושוב על הפקדים שבדרך, עד שהוא מגיע לפקד שיצר אותו. אירוע כזה לדוגמא נקרא PreviewMouseRightButtonDown. נעיר שהרבה סוגים של אירועים (כמו לחיצה עם העכבר) מגיעים בזוגות. אירוע אחד מסוג Bubbling ואירוע נוסף מסוג Tunneling בעל קידומת Preview בשם של האירוע.
  3. אירוע מסוג Direct – אירוע מסוג זה הוא אירוע שפועל רק על הפקד שיצר אותו ואינו מחלחל על עץ הפקדים בשום כיוון. סוג זה דומה לאופן שבו האירועים הרגילים עובדים.

אם אינכם בטוחים מה סוג האירוע שאליו אתם נרשמים ניתן לבדוק זאת בתיעוד של האירוע.

ניתן כמובן ליצור Routed Events משלכם, אבל זה חורג מגבולות המדריך.

תגיות: , , , ,

arikp

אריק פוזננסקי הוא יועץ בכיר ומרצה בסלע. הוא השלים שני תארי B.Sc. במתמטיקה ומדעי המחשב בהצטיינות יתרה בטכניון. לאריק ידע נרחב בטכנולוגיות מיקרוסופט, כולל .NET עם C#, WPF, Silverlight, WinForms, Interop, COM/ATL, C++ Win32 ו reverse engineering.

תגובות בפייסבוק