DCSIMG
November 2011 - Posts - אלעד כץ | Elad Katz
Sign in | Join | Help

אלעד כץ | Elad Katz

לגו של גדולים

November 2011 - Posts

פיתוח בHTML5 לחלונות 8 - צעדים ראשונים

פורסם בתאריך Nov 30 2011, 10:34 PM על ידי eladkatz

החדשות הטובות בפיתוח בHTML5 לחלונות 8, זה שHTML5 אנחנו כבר יודעים, וזה המון. עם יחסית מעט מאמץ, ניתן להפוך אתרי אינטרנט לאפליקציות, אם כי בשביל להשתמש בכל היכולות של חלונות 8 נצטרך ללמוד לא מעט.

פוסט זה הוא חלק מסדרת הפוסטים “תכנות לחלונות 8 בHTML5”.

נתחיל מההתחלה;

יצירת אפליקציה ראשונה

בVisual Studio 11 נפתח פרוייקט חדש (צריך להריץ אותו תחת חלונות 8 כמובן) ונבחר בפרוייקט JavaScript ריק:

image

 

Visual Studio יוצר לנו לא מעט קבצים, כשהחשובים שבהם הם default.html ו- default.js, ששניהם כבר פתוחים.
באפליקציית Win8 לא עוברים בין דפים בצורה הרגילה שאנו רגילים אליה מאתרי אינטרנט סטנדרטיים, אלא יש לנו דף ראשי אחד בלבד, והכל קורה רק בו. לאפליקציות מהסוג הזה (כדוגמת ג’ימייל או פייסבוק) קוראים אפליקציות דף אחד (Single Page Applications) והן מתנהגות הרבה יותר כמו אפליקציות רגילות. לאפליקציות מהסוג הזה יש לא מעט פלוסים, יחד עם לא מעט קשיים שמתלווים אליהם מבחינת ארכיטקטורה שנדבר עליהם בהמשך.

בדף הראשי יש כבר לא מעט קוד:

image

בשורה 7 יש קישור לקובץ CSS שמכיל את המראה הסטנדרטי הכהה של אפליקציות חלונות 8.
שורות 8-9 מכילות קישורים לקבצי JS בשם base.js ו- wwaapp.js שהם חלק מספריה בשם WinJS. הספרייה הזו חשובה מאוד – היא מאפשרת לנו ליצור קונטרולים של חלונות 8, יחד עם עוד הרבה מחלקות עזר שנשתמש בהן לעיתים קרובות. WinJS עקרונית יכול לעבוד גם באתרי אינטרנט רגילים, ונכון לעכשיו אין שום דבר בקוד שלנו שלא יכול לרוץ גם כאתר אינטרנט רגיל.

שורה 11 מכילה קישור ל default.css – קובץ הCSS הראשי של האפליקציה שלנו, שכרגע הוא די ריק.
שורה 12 מכילה קישור לdefault.js שכבר פתוח אוטומאטית – הקובץ הזה יכיל את הקוד לדף הראשי, מעין CodeBehind.

בשביל להריץ את האפליקציה הפשוטה בעולם נשנה את ה Body כך שיהיה:

<body>
    <h1>
        שלום חלונות 8
    </h1>
</body>

ונריץ. האפליקציה תארז ותתקין את עצמה על המחשב:

image

נעצור את האפליקציה ע”י Alt + F4 ונחזור ל Visual Studio. האפליקציה עצמה בנויה *מאוד* דומה לאתר אינטרנט רגיל, ואלו החדשות הטובות – אנחנו כבר יודעים לכתוב אתרי אינטרנט רגילים Smile 
החלק המעניין הוא כמובן ב default.js:

image

ננתח את הקוד:
שורה אחת ושורה 13 מגדירות פונקציה מיידית. פונקציה מיידית היא פונקציה ללא שם, שמריצה את עצמה מיידית לאחר ההגדרה. פונקציה מיידית היא Design Pattern שימושי מאוד בJavaScript, שמטרתו לודא שהקוד שאנחנו כותבים לא “מלכלך” את מרחב השמות הגלובאלי במשתנים גלובאליים. כל משתנה או פונקציה שנגדיר בתוך גוף הפונקציה המיידית “נראה” רק בתוך הפונקציה ולא מחוץ אליה. במובן מסויים זה דומה להגדרת namespace ב C#. (קרא עוד על פונקציה מיידית)

בשורה 2 יש את הפקודה ‘use strict’, שמוודאת שאנחנו עובדים בJavaScript 5. (או ליתר דיוק ECMA Script 5). הפקודה נרשמת כמחרוזת על מנת לוודא שדפדפנים שלא מכירים את JS5 כמו IE6 לא יקרסו בשורה הזו, אלא פשוט יתעלמו ממנה. כאמור, אנחנו רצים בתוך מנוע של IE10, אבל הפקודה נראית כך בכל מקרה.
JS5 לא מוסיף יותר מדי יכולות לשפה, חוץ מתיקונים שונים ואיסור על כל מיני טריקים בעייתיים בגאווה סקריפט – הוא מונע מהם לעבוד וכך לא נכנסים למקומות בעייתיים שגרסאות קודמות של JS מאפשרות.
המשמעות הכי רלוונטית עבורנו לכך שאנו עובדים ב JS5 היא שחייבים להצהיר על משתנים לפני שמשתמשים בהם. אי אפשר פשוט להתחיל להשתמש במשנה לפני שהצהרנו עליו. (די מזכיר את Option Explicit מ VisualBasic של פעם).

שורה 4 – Debug.enableFirstChanceException – מאפשרת לנו לתפוס שגיאות של JS שבאופן רגיל היו מוחרשות. זה יאפשר לנו לדבג את האפליקציה ביתר קלות במידה ויהיו לנו באגים. (ויהיו. מספיק.)
כדאי להפוך את השורה הזו לאמיתית (להסיר את ההערה) על מנת שנתפוס בעיות מיד כשהן קורות.

בשורה 6-10 אנחנו פוגשים לראשונה את WinJS שנחקור אותו עוד הרבה בהמשך.

WinJS.Application.onmainwindowactivated = function (e) {
     if (e.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch) {
         // TODO: startup code here
     }
 }

הקוד נרשם לאירוע onmainwindowactivated – שקורה כל פעם שאפליציה שלנו מופעלת. הפעלת אפליקציה יכולה לקרות מכל מיני סיבות; הפעלה רגילה בהתחלה, חזרה ממצב מושהה (אפליקציות בחלונות 8 נכנסות להשהייה כשהן לא נמצאות על המסך, גם כשהן לא סגורות) וכו’.
בשורה השנייה אנחנו בודקים אם האירוע נורה כתוצאה מפתיחה רגילה של האפליציה, ובמידה וכן מאפשר לנו להריץ קוד התחלתי, שנוסיף עוד מעט.

השורה האחרונה:

WinJS.Application.start();

מתחיל את אובייקט האפליציה של WinJS מה שיאפשר לתפוס אירועים כמו זה שנרשמנו אליו עכשיו.



הרצת קוד משלנו באפליקציה

נשנה את הHTML כך של H1 יהיה גם ID:

<h1 id="theHeader">
    שלום חלונות 8
</h1>

ואיפה שרשום TODO: startup code here // נוסיף קוד שלנו:

document.getElementById("theHeader").innerText = "Code from default.js CodeBehind";

נריץ ונקבל את המסך הבא:

image

השורה האחרונה שהוספנו היא אולי השורה הכי “קלאסית” בג’אווה סקיפט, אבל לא רואים אותה לעיתים יותר מדי קרובות היום – במקום זה נהוג להשתמש בספרייה המעולה jQuery (או ספריות דומות). אפליקציות של חלונות 8 הן קודם כל HTML וJS רגילים, ולפיכך jQuery יכול להשתלב כאן בקלות. נראה בהמשך גם איך עושים את זה, וגם שלא כל כך חייבים את jQuery כשיש לנו את WinJS.

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

טיפ: יצירת טבלת כל הערים בישראל בSQL - המרת רשימה רגילה לטבלת SQL

פורסם בתאריך Nov 22 2011, 12:50 PM על ידי eladkatz

טיפ SQL–איך לקחת רשימה מאתר ולהפוך אותה לטבלה בדרך המהירה ביותר

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

הבעיה היא שמרשימה כזו:

image

לא תמיד ברור איך יוצרים טבלת SQL.

טריק קטן שאני משתמש בו תמיד הוא לקחת את הרשימה, ולהעתיק אותה לתוך אקסל: (Copy + Paste פשוט)

image

 

אקסל מאפשר לכתוב נוסחאות פשוטות, שיאפשרו לנו להרכיב משפט SQL תקני בקלות, ולשכפל אותו.
לדוגמא, אם נרצה להכניס את הערך הראשון לטבלת SQL, השאילתא צריכה להיראות  כך:

INSERT INTO Cities (Name) Values ('תל אביב');

בתא B1 נכתוב נוסחא פשוטה שתשתמש בערך שנמצא ב A1 :

=CONCATENATE("INSERT INTO Cities (Name) Values ('", A1, "');")

הפונקציה Concatenate מקבלת כמה מחרוזות ומחזירה את החיבור של כולן:

image

היופי הוא שעכשיו אפשר לקחת את הנוסחא שבתא B1, ולהעתיק אותה על כל טור B. אקסל מספיק חכם להחליף את A1 לתא בטור A בשורה הרלוונטית:

image

עכשיו נוכל לסמן את כל טור B ולהעתיק אותו – אקסל מספיק חכם להעתיק את הטקסט שנוצר ולא את הנוסחא לתוך הקליפבורד, ונעתיק אותו לתוך חלון שאילתא של SQL:

image

הבעיה היא שלחלק מהישובים יש מקף בשם, לדוגמא בית ג’ן, מה שהורס לנו את הSQL:

image

בשביל לרשום מקף בSQL נוכל לבצע Escaping לתו. בSQL עושים זאת פשוט על ידי שני מקפים. נבחר את טור A ונחליף מקף בשני מקפים:

image

ונעתיק את טור A בחזרה לSQL.

עכשיו נוכל להריץ, וכך במכה אחת מכניסים את כל הערים לטבלה.

את קובץ הערים אפשר להוריד מכאן

חלונות 8 - המדריך השלם לפיתוח ב HTML5

פורסם בתאריך Nov 21 2011, 09:49 PM על ידי eladkatz

לכל אחת מטכנולוגיות הפיתוח של חלונות 8 - C++, C#, HTML5  יש פלוסים ומינוסים ברורים, ואני מניח שיצא לי לפתח לא מעט לשלושתן.
יחד עם זאת, HTML5 נראה לי מרתק במיוחד, היות וזה הפתח היחידי לטכנלוגיה שהיא באמת Cross-Platfrom בסופו של יום, ולכן בסדרת הפוסטים הנוכחית נתרכז בטכנולוגיה הזו.

  1. 1. WinRT וטכנולוגיות הפיתוח של חלונות 8
  2. 2. התקנת חלונות 8 דרך מכונה וירטואלית
  3. 3. איך מפעילים את תפריט התחל הישן
  4. 4. איך לשנות את תפריט התחל בצורה אוטומאטית
  5. 5. Hello World בHTML5
  6. 6. המבנה של אפליקצית מטרו בHTML5
  7. 7. מבנה תיקיית האפליקציות במחשב 
  8. 8. מבוא ל WinJS 
  9. 9. מבנה WinJS
  10. 10. יצירת קורא RSS חלק ראשון
  11. 11. שימוש ב jQuery ובספריות צד שלישי נוספות
  12. 12. יצירת קורא RSS חלק שני – שימוש ב WinRT

 

רשימת הפוסטים הנ”ל נכונים לפיתוח מול גרסת האלפא של חלונות 8 (Developer Preview). בגרסת הבטא השתנה לא מעט, ולפיכך את הפוסטים אמשיך רק לאחר יציאת גרסת ה RC (שמתוכננת לחודש מאי). רוב החומר עקרונית די דומה, אבל יש כאמור מספיק שינויים המצדיקים פוסטים חדשים על הנושא (בתקוה סדרת הפוסטים החדשה תהיה בצורת סירטונים.

 

    מאחורי הקלעים של חלונות 8 - WinRT וטכנולוגיות הפיתוח החדשות

    פורסם בתאריך Nov 21 2011, 09:24 PM על ידי eladkatz

    פוסט זה הוא חלק מסדרת הפוסטים “תכנות לחלונות 8 בHTML5”.

    הרבה דובר על ממשק המשתמש החדש של חלונות 8 – מטרו – אבל חלונות 8 מביאה הפתעות מתחת לקלעים לא פחות מאשר מעל. החידוש הכי משמעותי הוא כמובן WinRT, הAPI שמחליף את Win32, ומאפשר  3 דרכים שונות לכתיבת אפליקציות, כל אחת עם הפלוסים ועם המינוסים שלה;

    1. 1. C# + XAML.

    2. 2. C++ + XAML

    3. 3. JavaScript + HTML5

     

    המודל התכנותי הישן של חלונות 7 עדיין נמצא כאן (כל אפליקציה של חלונות 7 עדיין תעבוד בחלונות 8), אבל בממשק הישן (Legacy).
    בממשק החדש, מטרו, תתאפשר עבודה עם הפלטפורמות החדשות. לכולן יש גישה מלאה ל API של חלונות החדש, שנקרא WinRT.
    סביבת דוט נט סבלה מנחיתות ביחס לC++ בעשר שנים האחרונות, היות והAPI הישן Win32 לא היה דוט נטי (ואפילו לא C++ לגמרי. הממשק הוא ממשק Com-י שנראה הרבה יותר כמו C).
    לא עוד. לדוט נט יש גישה לAPI באותה רמה שיש לC++, ואלה חדשות מאוד טובות למתכנתי דוט נט. WinRT עדיין כתוב בC++, אך עכשיו הוא כתוב כך שמבחינת מתכנתי הדוט נט זה שקוף לחלוטין.

    הבשורה המשמעותית יותר היא לHTML. בניגוד למה שחשבתי בפעם הראשונה ששמעתי את המושג Native HTML בכנס מיקס 2011 - שזה סה”כ עוד דרך של מיקרוסופט להגיד שהפלטפורמות שלהם יתמכו בHTML5 בצורה הטובה ביותר - מיקרוסופט הבטיחו וקיימו הרבה מעבר למה שיכולתי לחלום. HTML5/JS מקבל גישה ישירה לWinRT בדיוק כמו הפלטפורמות האחרות, ויכול לעשות (כמעט) כל מה שהפלטפורמות האחרות יודעות לעשות. ביוני 2011 כבר רשמתי שחלונות 8 היא רעידת אדמה למפתחים, ועכשיו אפשר לראות את זה קורה. חלונות 8 הינה מערכת ההפעלה המשמעותית הראשונה שמאפשרת פיתוח אמיתי בHTML5, והאפשרויות העומדות בפני מפתחי HTML5 גדולות מתמיד.

    הדיאגרמה שלעיל פורסמה במהלך הרצאת המליאה הראשית בכנס בילד, וזכתה כמעט מיד לביקורת על היותה לא מדויקת. מהדיאגרמה לא ברור האם הCLR עדיין כאן. DirectX נעלם לגמרי התמונה ולא ברור לאיזו טכנולוגיה יש גישה לDirectX. להוסיף עוד חטא על פשע סילברלייט בכלל לא מופיע אפילו בצד הלגאסי… (Haven’t the Silverlight people suffered enough?! Smile )

    הביקורת נכונה, אבל הדיאגרמה סה”כ הגיונית (קשה ליצור דיאגרמה שתהיה גם נכונה טכנית וגם מספיק “שיווקית” וקלה לתיאור). דאג סבן מחברת טלריק העלה דיאגרמה יותר מדויקת שנראית כך:

     

    לצד זה שסילברלייט אכן נמצא כאן (ולא בצד שמאל.. סילברלייט לא קיים במטרו), מהדיאגרמה הזו הרבה יותר פשוט להבין את הדימיון ואת השוני בין הטכנולוגיות האפשרויות. לכל אחת מהטכנולוגיות יש את היכולות שלה, וסיבות שונות לבחור בה:

    C# + XAML

    השם המוזר הזה (לא WPF, ולא סילברלייט. זאמל!) בא בשביל לאפשר למיקרוסופט בצורה אלגנטית לא לדבר על איזו טכנולוגיה החליפה איזו טכנולוגיה. המודל התכנותי (לעבוד מעל מערכת הפעלה ולא בתוך פלאגין של דפדפן) הוא של WPF, אבל הקוד מבוסס דוקא על סילברלייט (או כפי שכבר שמעתי מישהו סרקסטי מתבטא – הרגו את סילברלייט, ביתרו את הגופה, ומחלקי הגופה יצרו את C# + XAML Smile ).
    במובן מסויים יש כאן את המינוסים של WPF (רק לחלונות) ואת המינוסים של סילברלייט (לא מבוסס על קוד דוט נטי מלא) ביחד, ואלו החדשות הרעות. יחד עם זאת, יש בזה לא מעט הגיון.
    חשוב לציין כי הקוד לא תואם לWPF או לסילברלייט, אך שינוי קוד קיים והתאמתו (Porting) לא מורכב במיוחד, ויש כבר בלוגים המתארים את התהליך.

    הפלוסים:
    1. מתכנתי WPF וסילברלייט ירגישו בבית.
    2. הדרך הקלה והפרודקטיבית ביותר לכתוב לחלונות 8 (וזה לא ישתנה בזמן הקרוב). לכל מי שהספיד את דוט נט – זה היה טיפה מוקדם מדי Smile

     

    C++ + XAML

    C++ מקבלת עדנה מחודשת. יחד עם שחרור C++11, השפה הישנה והטובה מקבלת כאן חיזוק משמעותי. C++ היא מהירה, אבל עד היום במידה והיינו רוצים תמיכה ביכולות גראפיקה, שפה דקלרטיבית לUI, ויכולות Layout מודרניות - ++C הייתה בעייתית (למרות ש QT סיפק לא מעט). הרבה מאוד חברות שעברו מ++C לWPF בשנים האחרונות עשו את המעבר הקשה בעיקר בשל כך. 
    החל מחלונות 8 ++C מקבלת יכולות מודרניות לחלוטין, ואם C# מיישרת קו עם C++ בכל מה שקשור לגישה למערכת ההפעלה, C++ מיישרת קו עם C# בכל מה שקשור לגראפיקה ולגישה מודרנית ל UI.

    יחד עם זאת, C++ היא עדיין שפה לא מנוהלת והרבה יותר קשה לכתוב בה. אני רגיל שהGarbage Collector מנקה אחרי, ואין לי כל כך רצון לחזור לכאב ראש הזה..
    אז למה כן לכתוב ב++C?

    הפלוסים:
    1. היחידה עם גישה לDirectX, ולפיכך משחקים עם ביצועים מקסימליים יכתבו כמעט אך ורק בC++. קוד לא מנוהל עדיין מאפשר שליטה מלאה יותר על מה שקורה מאחורי הקלעים, וזה כנראה אף פעם לא ישתנה. מה עם XNA אתם שואלים? בינתיים אין תוכניות כאלו…

     

    JavaScript + HTML5

    אין ספק כי זו הפלטפורמה המדוברת והמעניינת ביותר. HTML5 מקבל גישה בפעם הראשונה אי פעם למערכת הפעלה סטנדרטית (ולא, ChromeOS לא נחשב). החלום של “כתוב פעם אחת, הרץ בכל מקום” מעולם לא היה קרוב יותר להתממש. HTML5 בחלונות 8 יכול לרוץ בשני מודלים שונים. דרך הדפדפן, וישירות מעל מערכת ההפעלה כאפליקציית מטרו בדיוק כמו C# ו++C.
    שתי הדרכים דומות למדי. (אותו מנוע של IE10 מאחורי הקלעים), אם כי הדרך השניה היא החידוש הגדול. כאשר HTML5 רץ כאפליקציה, יש לו גישה מלאה לWinRT ולכל היכולות המיוחדות של מערכת ההפעלה. למיטב הבנתי כל דבר שאפשר לכתוב בC# יהיה אפשר לכתוב גם בHTML5, וזו אפשרות מדהימה.

    יחד עם זאת, לכתוב בJavaScript עדיין הרבה יותר קשה מC#. שפת JavaScript היא שפה דינאמית ולא מקומפלת, מה שאומר בין השאר שהרבה יותר קשה לכתוב לה תמיכה טובה בכלי פיתוח - אינטליסנס, ריפקטורינג, וכו’ (Intelisense, Refactoring). זו שפה ללא יכולות שכבר התרגלנו לראות בשפות מודרניות כגון Generics, Interfaces וכו’ ולכתוב אפליקציות מלאות וגדולות בJavaScript עדיין הרבה יותר קשה מאשר בC#.
    גם כאן, מיקרוסופט מציעה לא מעט. כלי הפיתוח החדשים – Visual Studio 11, ו Expression Blend 5 מהווים קפיצת מדרגה משמעותית בכל מה שקשור לתכנות בHTML5.
    ממה שראיתי עד עכשיו כלי הפיתוח החדשים מספקים אפשרויות אינטליסנס וריפקטורינג מרשימים למדי, והרבה פיצ’רים שהתרגלנו אליהם בC# סוף סוף מגיעים לJS.

    הפלוסים:
    1. לכתוב פעם אחת ולהריץ בכל מקום. (עם התאמות, לא גדולות במיוחד)
    2. לשפות לא מקומפלות יש גם פלוסים. אחד הפלוסים המשמעותיים ביותר מגיע עם Blend5 שיאפשר לעצב אפליקציה תוך כדי ריצה!
    היכולת הזו לא פחות ממדהימה, ולמעשה מאפשרת את היכולת הכי חזקה של MVVM – בלנדאביליות (Blendability) בלי טיפת מאמץ ועם הרבה יותר כוח. (הפיצ’ר המדהים ביותר שראיתי מזה הרבה זמן. ארחיב עליו בפוסט עתידי)
    3. היות וHTML5 עובד דרך IE10, מובטחים לנו את כל הפיצ’רים של HTML5 עם סטנדרטים מלאים, אין צורך בהתאמה לאחור במידה וכותבים לחלונות 8.
    4. לכתוב פעם אחת ולהריץ בכל מקום כבר אמרנו? Smile


    למתכנתים יש נטייה לעיתים קרובות להתאהב בטכנולוגיה בה הם כותבים (וגם אני חוטא בזה מדי פעם), אבל חשוב לזכור שטכנולוגיה היא רק כלי. במידה ואני יכול לעשות עם שפה X מה שאני רוצה לא באמת אכפת לי איזו שפה זו.
    לכל אחת מהטכנולוגיות יש פלוסים ומינוסים ברורים, ואני מניח שיצא לי לפתח לא מעט לשלושתן.
    יחד עם זאת, HTML5 נראה לי מרתק במיוחד, היות וזה הפתח היחידי לטכנלוגיה שהיא באמת Cross-Platfrom בסופו של יום, ולכן בסדרת הפוסטים הנוכחית נתרכז בטכנולוגיה הזו.

    איך לשנות את תפריט התחל בחלונות 8 בצורה אוטומאטית - יצירת קבצי רג'יסטרי

    פורסם בתאריך Nov 19 2011, 01:19 PM על ידי eladkatz

    כהמשך לפוסט הקודם, מסתבר שבמידה ומפעילים את התפריט הישן אז תוכנות מטרו לא פועלות יותר (כאמור, זו גרסת מפתחים מאוד ראשונית).
    יחד עם זאת, להפעיל את תפריט התחל הישן מאוד שימושי, ולכן עדיף לעשות את שינוי הרג’יסטרי בצורה טיפה יותר אוטומאטית, ע”י קבצי reg שנכתוב ידנית.

    בשביל ליצור כזה קובץ, ניצור קובץ חדש בשם ShowWin7StartMenu.reg, ובתוכו נרשום:

    Windows Registry Editor Version 5.00
    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer]
    "RPEnabled"=dword:00000000

    ובשביל ליצור את הקובץ שמחזיר את המצב לקדמותו, ללא תפריט התחל ועם ממשק מטרו עובד, ניצור עוד קובץ בשם HideWin7StartMenu.reg :

    Windows Registry Editor Version 5.00
    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer]
    "RPEnabled"=dword:00000001
    הפעלה של הקבצים תרשום את הערכים הרלוונטים לרג’יסטרי בצורה אוטומאטית ומהירה.

    איך מפעילים את תפריט התחל הישן בחלונות 8

    פורסם בתאריך Nov 18 2011, 11:40 PM על ידי eladkatz

    גרסת הפיתוח ששוחררה לאויר של חלונות 8 עדיין לא ממש אפויה לחלוטין. כשמתחילים לפתח, מהר מאוד מגלים שעדיין לא ברור איך לעשות את כל מה שידענו לעשות בחלונות 7, ולפיכך יכול להיות מאוד נוח אם נוכל להשתמש בתפריט התחל הקלאסי של חלונות 7, שעל פי ברירת מחדל לא מופעל.

    על מנת להפעיל אותו, יש להכנס לRegedit.exe, ולערוך את הרג’יסטרי.
    כבר כאן אפשר להתקע – איך אני מפעיל תוכנה שלא מופיע באריחים (מה שמחליף את האייקונים בחלונות 8), כשאין לי גישה גם לתפריט התחל?!

    בממשק המטרו, כאשר מתחילים להקליד משהו, מיד נפתח חלון החיפוש. (מטרו מותאם גם למקלדת, גם לעכבר, וגם למגע, בניגוד לדעה הרווחת):

    image

    צריך לפתוח את HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer

    ושם לשנות את RPEnabled מ”1” ל “0”.

    שימו לב כי עכשיו לחיצה על כפתור ההתחל על המסך תפתח את תפריט התחל הישן. הדרך היחידה כעת לעבור למסך מטרו היא ללחוץ על מקש חלונות על המקלדת.

    image

    בשביל לחזור למצב הקודם פשוט צריך להחזיר את RPEnabled ל”1”.

    JS - איך לממש מיון מהיר בג'אווה סקריפט - QuickSort

    פורסם בתאריך Nov 17 2011, 02:25 AM על ידי eladkatz

    שאלה שנשאלה בפורום דוט נט של תפוז:

    “אני מקבל נתונים בAJAX, ומציג אותם בטבלה בHTML. את הנתונים אפשר למיין, אך כאשר יש לי הרבה רשומות (600), הדפדפן קופא לכמה שניות טובות ומפסיק להגיב..  האם יש דרך לעשות כאן איזו משהו אסינכרוני דוגמת thread?
    אולי כדאי לבצע מיון בצד שרת עם ajax?
    איך מקובל לעשות את זה בצורה מקצועית?”

     

    ג’אווה סקריפט אכן איטית בהרבה מאשר קוד מקומפל רגיל ב#C, אבל התשובה לא טמונה בפתרונות יצירתיים יותר מדי. פשוט צריך לבצע מיון בצורה נכונה.

    איך אתה מבצע את המיון?
    מיון נאיבי יתבצע בזמן של n*n, במקרה שלנו n=600 ולפיכך 360000 פעולות, שבהחלט יכול להסביר את זה שהדפדפן קופא.

    מיון יעיל יתבצע בזמן של n*log n שיחסוך המון - 5500 פעולות שאמור להיות די מיידי (או בכל אופן פי 65 יותר מהיר)
    כמובן שלא שייך כאן ת'רדים נוספים.

    גם בשרת לא כדאי לעשות את זה, חוץ מסיטואציה בה אנחנו צריכים למיין *באמת* הרבה רשומות, ובשרת זה כבר נמצא ממוין (לדוגמא, בתוך SQL כשיש אינדקס רלוונטי). יחד עם זאת מדובר בסיטוציה בה ברור לחלוטין שצריך לבצע את זה בשרת (עשרות אלפי רשומות +. אנחנו בכל מקרה לא נעביר את כולן ללקוח). במקרה שלנו פשוט צריך לממש מיון יעיל, כדוגמת QuickSort :

       1: // global variables
       2: var col = 0;
       3: var parent = null;
       4: var items = new Array();
       5: var N = 0;
       6:  
       7: function quicksort(m, n, desc)
       8: {
       9:   if(n <= m+1) return;
      10:  
      11:   if((n - m) == 2) {
      12:     if(compare(get(n-1), get(m), desc)) exchange(n-1, m);
      13:     return;
      14:   }
      15:  
      16:   i = m + 1;
      17:   j = n - 1;
      18:  
      19:   if(compare(get(m), get(i), desc)) exchange(i, m);
      20:   if(compare(get(j), get(m), desc)) exchange(m, j);
      21:   if(compare(get(m), get(i), desc)) exchange(i, m);
      22:  
      23:   pivot = get(m);
      24:  
      25:   while(true) {
      26:     j--;
      27:     while(compare(pivot, get(j), desc)) j--;
      28:     i++;
      29:     while(compare(get(i), pivot, desc)) i++;
      30:     if(j <= i) break;
      31:     exchange(i, j);
      32:   }
      33:  
      34:   exchange(m, j);
      35:  
      36:   if((j-m) < (n-j)) {
      37:     quicksort(m, j, desc);
      38:     quicksort(j+1, n, desc);
      39:   } else {
      40:     quicksort(j+1, n, desc);
      41:     quicksort(m, j, desc);
      42:   }
      43: }
      44:  
      45: function sortTable(tableid, n, desc)
      46: {
      47:   parent = document.getElementById(tableid);
      48:   col = n;
      49:  
      50:   if(parent.nodeName != "TBODY")
      51:     parent = parent.getElementsByTagName("TBODY")[0];
      52:   if(parent.nodeName != "TBODY")
      53:     return false;
      54:  
      55:   items = parent.getElementsByTagName("TR");
      56:   N = items.length;
      57:  
      58:   // quick sort
      59:   quicksort(0, N, desc);
      60: }

    עבודה עם גריד חכם בצד הלקוח ב JS – jqGrid - התקנה

    פורסם בתאריך Nov 15 2011, 07:34 PM על ידי eladkatz

    עבודה עם גריד חכם בצד הלקוח היא הרבה יותר אפקטיבית מאשר עבודה עם גריד צד שרת, כמו זה המובנה בתוך asp.net

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

    אז ככה. לjQuery UI עדיין אין קומפננטת גריד בחבילה. זה נמצא בתכנון, אבל יש עוד זמן עד שזה יהיה רלוונטי. רמת הגימור ב jQueryUI היא מאוד גבוהה ויש למה לחכות, ולעיתים קרובות ברגע שיוצאת גרסה חדשה היא הופכת לסטנדרט די מהר. בינתיים יש לא מעט רכיבי גריד טובים בשוק שהם פלאגינים מעל jQuery, עם פלוסים ומינוסים לכל אחד.

    בדקתי את הגרידים הבאים :

    FlexiGrid, jqGrid, SlickGrid, DataTables

    גריד אמיתי תומך בעריכה בצד הלקוח, ולפיכך FlexiGrid ו DataTables יורדים. מהרבה בחינות אלו סה”כ טבלאות מסוגננות, כך שזה לא באמת מה שאנחנו מחפשים.

    SlickGrid יפהפה, אבל לצערי *הרב* אין לו תמיכה נכון לעכשיו בשפות איזוטריות ולא חשובות שמשום מה כותבים בהן מימין לשמאל. בפרוייקט שלי אני צריך כזו תמיכה (מה לעשות, עברית) אז זה יורד מהפרק, ונשארנו רק עם jqGrid.

    התקנת jqGrid :

    ההתקנה די פשוטה; בדף ההורדה בוחרים הכל ולוחצים על Download (אפשר לבחור פחות מהכל ואז קבצי הJS והCSS קטנים יותר. לפיתוח ולימוד עדיף להוריד הכל, אבל חשוב לפני העלאה לפרודקשן להוריד רק את המינימום ההכרחי – שימו לב כי הגרסה המכווצת היא של 240KB ג’אווה סקריפט!!).

    image

    שימו לב כי חברת Trirand, שמתחזקת את הגריד מוכרת גם רכיבי צד שרת שעוטפים את הגריד. הרכיבים האלו הינם בתשלום, ולדעתי לא טובים יותר מדי (בדקתי רק את הרכיב של MVC). אין שום סיבה לשלם עליהם, והגריד הבסיסי לג’אווה סקריפט הוא חינמי לחלוטין.

     

    בקובץ הזיפ שהורדנו ישנן 4 ספריות:

    image

    הקבצים אותם נצטרך הם:

    1- ui.jqgrid.css – תחת ספריית הCSS – מכיל את העיצוב.

    2. jquery.jqGrid.min.js – קובץ ה JS הראשי של הגריד, תחת ספריית JS.

    3. grid.locale-he.js – תחת ספריית js\i18n – מכיל טקסטים בעברית לגריד

    4. grid.locale-en.js – תחת ספריית js\i18n – מכיל טקסטים באנגלית (וכמו כן, באותה ספרייה נמצא את קובץ הלוקאליזציה עבור כל שפה נוספת שנרצה).

     

    יחד עם זאת, לjqGrid יש תלות גם ב jQuery, וגם בCSS של jQueryUI -

    1. jquery-1.7.min.js – הקובץ הראשי של jQuery. (מצורפת גם גרסה ישנה כלשהי של jQuery בתוך הזיפ)

    2. jquery.ui.all.css – קובץ הCSS הראשי של jQuery UI, שלא מצורף בקובץ הזיפ.

    על מנת להפעיל את הגריד יש לעשות שלושה דברים, לכתוב את הHTML לגריד, לכתוב את ה JS שמפעיל אותו, ולכתוב את צד השרת. בדוגמה להלן אני משתמש ב ASP.net MVC, אבל אפשר בהתאמות קלות להפעיל גם בכל פלטפורמת צד שרת אחרת)

     

    הפעלת הגריד – הגרסה הנאיבית

    1. HTML

    לינקים לכל הקבצים הרלוונטים -

       1:  
       2:     <link href="../../Content/themes/base/jquery.ui.all.css" rel="stylesheet" type="text/css" />
       3:     <link href="../../Content/ui.jqgrid.css" rel="stylesheet" type="text/css" />
       4:     <script src="../../Scripts/jquery-1.7.js" type="text/javascript"></script>
       1:  
       2:     <script src="../../Scripts/i18n/grid.locale-he.js" type="text/javascript">
       1: </script>
       2:     <!--script src="../../Scripts/i18n/grid.locale-en.js" type="text/javascript"></script-->
       3:     <script src="../../Scripts/jquery.jqGrid.min.js" type="text/javascript">
    </script>

     

    והאלמנטים עליהם “יתלבש” jqGrid :

       1: <div>
       2:     
       3:     <table id="list" ></table>
       4:     <div id="pager" ></div>
       5:  
       6: </div>

     

    2. JavaScript :

       1: <script type="text/javascript">
       1:  
       2:     $(function () {
       3:         $("#list").jqGrid({
       4:             direction: 'rtl',
       5:             url: '/DemoGrid/GetAllItems/',
       6:             datatype: 'json',
       7:             mtype: 'GET',
       8:             colNames: ['#', 'שם', 'מחיר'],
       9:             colModel: [
      10:                   { name: 'Id', index: 'Id', width: 60, align: 'right' },
      11:                   { name: 'Name', index: 'Name', width: 300, align: 'right', editable: true },
      12:                   { name: 'Price', index: 'Price', width: 200, align: 'right', editable: true}],
      13:             pager: $('#pager'),
      14:             rowNum: 10,
      15:             rowList: [5, 10, 20, 50],
      16:             sortname: 'Id',
      17:             sortorder: "desc",
      18:             viewrecords: true,
      19:             caption: 'הגריד הראשון שלי'
      20:         });
      21:     }); 
    </script>

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

    שורה 3- יצירת הגריד על ידי פלאגין של jQuery.

    שורה 5 – הURL אליו הגריד יגש על מנת להוריד נתונים בAJAX.

    שורה 4 – מגדיר עבודה מימין לשמאל, מתאים לעברית.

    שורה 9-12 – מגדיר את השדות והמיקום שלהם בגריד.

     

    3. צד השרת – ממומש בasp.net mvc, אבל כל web service בכל טכנולוגיה אחרת (asp.net, php, ruby) יראה מאוד דומה:

       1: public JsonResult GetAllItems()
       2: {
       3:     var jsonItems = GetProductsMock()
       4:         .Select(p => new
       5:         {
       6:             id = p.ID,
       7:             cell = new[] {
       8:                 p.ID.ToString(), 
       9:                 p.Name,
      10:                 p.Price.ToString(), 
      11:             }
      12:         }).ToArray();
      13:  
      14:     var jsonData = new
      15:     {
      16:         total = 2,
      17:         page = 1,
      18:         records = 10,
      19:         rows = jsonItems,
      20:     };
      21:  
      22:     return Json(jsonData, JsonRequestBehavior.AllowGet);
      23: }

     

    הקוד מחזיר רשימה של מוצרים, בצורה נאיבית, והופך אותם לJson בשביל לשלוח לצד הלקוח.

    את ה”מוצרים” פשוט יצרתי תוך כדי ריצה, אך כמובן שבקוד אמיתי היינו נגשים לדטה בייס וכו’

    מחלקת המוצר נראית כך:

       1: public class Product
       2: {
       3:     public int ID { get; set; }
       4:     public string Name { get; set; }
       5:     public double Price { get; set; }
       6: }

    והקוד שמחזיר רשימת מוצרים (למי שרוצה לשחזר את הקוד אצלו):

       1: private List<Product> GetProductsMock()
       2: {
       3:     var products = new List<Product>();
       4:  
       5:     products.Add(new Product { ID = 1, Name = "חציל", Price = 4 });
       6:     products.Add(new Product { ID = 2, Name = "קישוא", Price = 6.5 });
       7:     products.Add(new Product { ID = 3, Name = "מלפפון", Price = 3.3 });
       8:     products.Add(new Product { ID = 4, Name = "עגבניה", Price = 5 });
       9:     products.Add(new Product { ID = 5, Name = "אפרסמון", Price = 12 });
      10:     products.Add(new Product { ID = 6, Name = "אבטיח", Price = 24 });
      11:     products.Add(new Product { ID = 7, Name = "ענבים", Price = 22 });
      12:     products.Add(new Product { ID = 8, Name = "תפוח", Price = 13.2 });
      13:     products.Add(new Product { ID = 9, Name = "תפוז", Price = 6 });
      14:     products.Add(new Product { ID = 10, Name = "קלמנטינה", Price = 5.5 });
      15:     products.Add(new Product { ID = 11, Name = "בטטה", Price = 8 });
      16:     products.Add(new Product { ID = 12, Name = "תפוח אדמה", Price = 5 });
      17:     products.Add(new Product { ID = 13, Name = "בצל", Price = 4.4 });
      18:     products.Add(new Product { ID = 14, Name = "גזר", Price = 6.2 });
      19:     products.Add(new Product { ID = 15, Name = "אפונה", Price = 19.9 });
      20:     products.Add(new Product { ID = 16, Name = "כרובית", Price = 18 });
      21:     products.Add(new Product { ID = 17, Name = "פומלה", Price = 14.7 });
      22:  
      23:     return products;
      24: }

     

    אם נריץ עכשיו את האפליקציה אז נראה שהכל כבר מחובר, והגריד מראה מוצרים:

    image

    אם כי הגריד לא יגיב למיון מחדש או למעבר לדף אחר. כל פעם שננסה לעבור לדף אחר או למיין מחדש, תתבצע קריאה חדשה לGetAllItems, יחד עם פרמטרים רלוונטים (השדה שעל פיו ממיינים, מספר עמוד וכו’)

     

    הפעלה מלאה של הגריד

    על מנת שהגריד יגיב כמו שצריך, נשנה את המימוש הנאיבי של המתודה GetAllItems כך שהיא תשתמש בפרמטרים ותחזיר תוצאות רלוונטיות:

       1: public JsonResult GetAllItems(JqGridSearchParameters gridSearch)
       2: {
       3:     IEnumerable<Product> qry;
       4:  
       5:     if (gridSearch.SortDirection == SortOrder.Ascending)
       6:         qry = GetProductsMock().OrderBy(p => p.ID);
       7:     else
       8:         qry = GetProductsMock().OrderByDescending(p => p.ID);
       9:  
      10:     var jsonItems =
      11:         qry
      12:         .Skip((gridSearch.CurrentPage - 1) * gridSearch.PageSize)
      13:         .Take(gridSearch.PageSize)
      14:         .Select(p => new
      15:         {
      16:             p.ID,
      17:             p.Name,
      18:             p.Price,
      19:         }).ToList()
      20:         .Select(p => new
      21:         {
      22:             id = p.ID,
      23:             cell = new[] {
      24:                 p.ID.ToString(), 
      25:                 p.Name,
      26:                 p.Price.ToString(), 
      27:             }
      28:         }).ToArray();
      29:  
      30:  
      31:     var totalPages = GetProductsMock().Count / gridSearch.PageSize + 1;
      32:  
      33:     var jsonData = new
      34:     {
      35:         total = totalPages,
      36:         page = gridSearch.CurrentPage,
      37:         records = jsonItems.Length,
      38:         rows = jsonItems,
      39:     };
      40:  
      41:     return Json(jsonData, JsonRequestBehavior.AllowGet);
      42: }

    JqGridSearchPamaters היא מחלקת עזר שהגדרתי, שמכילה את הפרמטרים שהגריד שולח מצד הלקוח:

       1: public class JqGridSearchParameters
       2: {
       3:  
       4:     public string _search { get; set; }
       5:     public string nd { get; set; }
       6:     public int page { get; set; }
       7:     public int rows { get; set; }
       8:     public string sidx { get; set; }
       9:     public string sord { get; set; }
      10:  
      11:     public int CurrentPage { get { return page; } }
      12:     public int PageSize { get { return rows; } }
      13:     public string SortColumn { get { return sidx; } }
      14:     public SortOrder SortDirection
      15:     {
      16:         get
      17:         {
      18:             if (sord == "asc")
      19:                 return SortOrder.Ascending;
      20:             else
      21:                 return SortOrder.Descending;
      22:         }
      23:     }
      24:  
      25:  
      26: }
      27:  
      28: public enum SortOrder
      29: {
      30:     Ascending,
      31:     Descending
      32: }

    עכשיו הגריד יגיב למעבר לדפים אחרים, ובנוסף נוכל למיין, אך המיון תמיד יתבצע על פי ה ID. אפשר לבדוק איזו עמודה נלחצה ועל פי זה לבצע מיון, אך זה לא קוד אלגנטי יותר מדי.

    על ידי שימוש ב DynamicLinq (הסבר מפורט בפוסט אחר) אפשר לכתוב קוד אלגנטי יותר ולהחליף את שורות 5-8 ב GetAllItems בשורות הבאות:

       1: if (gridSearch.SortDirection == SortOrder.Ascending)
       2:     qry = GetProductsMock().AsQueryable().OrderBy(gridSearch.SortColumn);
       3: else
       4:     qry = GetProductsMock().AsQueryable().OrderBy(gridSearch.SortColumn + " DESC");

    כך שלא משנה מה האובייקטים איתם עובדים – אפשר יהיה למיין על פי כל שדה.

    בשלב הזה יהיה לנו גריד פועל, עם תמיכה מלאה בעברית.

    הגריד יכול לתמוך בהרבה מאוד אופציות נוספות, עריכה, מחיקה, הוספה, חיפוש וכו’ – בפוסטים הבאים.