DCSIMG
Question from .Net Tapuz forum: Winforms WebBrowser invoking Javascript and Javascript invoking Winforms - Justin myJustin = new Justin( Expriences.Current );

Question from .Net Tapuz forum: Winforms WebBrowser invoking Javascript and Javascript invoking Winforms

שאלה:

 יש לנו טופס Winforms שפותח דף Web (שהוא HTML קלאסי) שאנחנו פיתחנו.

היינו רוצים שה-Javascript בדף HTML יוכל להעביר מסרים לטופס Winforms ושזה יגיב.

אנחנו גם צריכים שה-Winforms יעביר ל-Javascript נתונים נוספים.

יש כלי מובנה ב-Framework לזה?

 

תשובה:

 נחדד את נושא השאלה: תקשורת Winforms בין Javascript.
לתקשורת הזו יש שני כיוונים: Javascript שמדבר עם Winforms והכיוון השני הוא Winforms שמדבר עם Javascript.

נשתמש בפקד ה-WebBrowser שבה כברירת מחדל עם דוט נט 2.0.
ניצור טופס חדש ונגרור WebBrowser לטופס.

בנוסף, ניצור קובץ HTML בסיסי.

<html>

<body>

    <h1> Hello world! </h1>

</body>

</html>

נשנה את ה-URL של ה-WebBrowser שלנו שיצביע לקובץ HTML שלנו.

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

מדהים.

עכשיו נהפוך את הדוגמה הזו מ"גן ילדים" לאפליקציה של העולם האמיתי.

נרצה שבדף HTML שלנו יהיה רשימה של כוננים קשיחים (Hard Drives)  אפשריים במחשב, בלחיצה על כונן מסויים, הדף HTML יתמלא ברשימת הקבצים והתיקיות בספרייה הראשית של הכונן.

בואו גם נחשוב ביחד על למה לא מספיק כאן ג'אווה סקריפט.
ג'אווה סקריפט רץ דרך Sand-Box של הדפדפן ולמרות שיש לו יכולות אי-אלו ויכולות גרפיות מרשימות, הדפדפן מוגבל מבחינת אבטחה.
למרות שאפשר לעשות הרבה עם ג'אווה סקריפט, כיווני הברירת מחדל של הדפדפנים מונעים דברים כמו הרצת תוכניות על מחשב הלקוח, סריקת הקבצים על מחשב הלקוח, גישה ישירה למדפסת וכך הלאה. 
אז נאלץ לחזור לאפליקציית Winforms שאם תרוץ עם ההרשאות המתאימות תוכל כן לבצע דברים אלו. 

הנה דף ה-HTML שלנו:

<html>

<body>

    <h1> Select a drive to list it's files: </h1><br />

    <span style="text-decoration:underline; cursor: pointer;">C:\</span><br />

    <span style="text-decoration:underline; cursor: pointer;">D:\</span><br />

    <span style="text-decoration:underline; cursor: pointer;">E:\</span><br />

</body>

</html>

סה"כ span עם קצת עיצוב שיראה כמו קישור. וככה זה נראה.

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

מסתבר שעל ה-WebBrowser יש מאפיין (גם באנגלית: Property) מעניין בשם WebBrowser.ObjectForScripting.
המאפיין המוזר הזה מאפשר לנו לגשת מתוך הדפדפן לממשק חלונאי.

נגדיר מתודה (גם באנגלית: Method) בשם myMethod על האלמנט החלונאי שמכוון ל-ObjectForScripting, ודרך גישה ל-window.external.myMethod בג'אווה סקריפט נוכל לקרוא למתודה הזו.

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

        private void Form16_Load(object sender, EventArgs e)

        {

            webForScripting.ObjectForScripting = this;

        }

בנוסף, אותו אלמנט חלונאי חייב להיות מסומן עם ComVisiableAttribute.

    [System.Runtime.InteropServices.ComVisibleAttribute(true)]

    public partial class Form16 : Form

    {

        public Form16()

        {

            InitializeComponent();

        }

 

        private void Form16_Load(object sender, EventArgs e)

        {

            webForScripting.ObjectForScripting = this;

        }

    }

 נגדיר על הטופס (שהוא ה-ObjectForScripting שלנו) מתודה בשם ListFilesOnHardDrive שמקבלת את אות הכונן ורושמת את הקבצים בתקייה הראשית של הכונן.

        public void ListFilesOnHardDrive(string DriveLetter)

        {

            DriveInfo driveToIterateOverItsRootFiles = new DriveInfo(DriveLetter);

            foreach (FileInfo curFileToPrint in driveToIterateOverItsRootFiles.RootDirectory.GetFiles())

            {

                tbxResults.AppendText(curFileToPrint.Name + "\r\n");

            }

        }

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

אם למשל היינו רוצים לקרוא למתודה הזו מתוך קוד דוט-נטי היינו עושים את זה ככה:

        private void Form16_Load(object sender, EventArgs e)

        {

            ListFilesOnHardDrive("C");

        }

וזה היה נראה ככה.

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

<html>

<body>

    <h1> Select a drive to list it's files: </h1><br />

 

    <span style="text-decoration:underline; cursor: pointer;"

            onclick="window.external.ListFilesOnHardDrive('C');">C:\</span><br />

 

    <span style="text-decoration:underline; cursor: pointer;"

            onclick="window.external.ListFilesOnHardDrive('D');">D:\</span><br />

 

    <span style="text-decoration:underline; cursor: pointer;"

            onclick="window.external.ListFilesOnHardDrive('E');">E:\</span><br />

</body>

</html>

 השתמשנו ב-window.external וקראנו למתודה דוט-נטית לחלוטין!

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

נוסיף מתודת ג'אווה סקריפט שמקבלת שם קובץ ומדפיסה אותו לתוך תגית <div> עם רשימת הקבצים.

 

<html>

<head>

<script type="text/javascript">

function PrintFileName(fileName)

{

    document.getElementById("divResults").innerHTML  += fileName + "<br />";

}

</script>

</head>

<body>

    <h1> Select a drive to list it's files: </h1><br />

 

    <span style="text-decoration:underline; cursor: pointer;"

            onclick="window.external.ListFilesOnHardDrive('C');">C:\</span><br />

 

    <span style="text-decoration:underline; cursor: pointer;"

            onclick="window.external.ListFilesOnHardDrive('D');">D:\</span><br />

 

    <span style="text-decoration:underline; cursor: pointer;"

            onclick="window.external.ListFilesOnHardDrive('E');">E:\</span><br />

 

    <h1> Files:</h1>

    <div id="divResults" />

</body>

</html>

אם היינו רוצים לקרוא למתודת ג'אווה סקריפט הזו מתוך ה-HTML היינו עושים משהו כזה:

    <body onload="PrintFileName('myFile.ext')">

אז עכשיו נשאלת השאלה איך נקרא למתודת ג'אווה סקריפט הזו מתוך הטופס החלונאי שלנו?

נשתמש ב-WebBrowser.Document.InvokeScript שמקבל את שם הפונקציה בג'אווה-סקריפט שנרצה להריץ ומערך ערכים שנשלח לפונקציה. נשכתב את ListFilesOnHardDrive.

        public void ListFilesOnHardDrive(string DriveLetter)

        {

            DriveInfo driveToIterateOverItsRootFiles = new DriveInfo(DriveLetter);

            foreach (FileInfo curFileToPrint in driveToIterateOverItsRootFiles.RootDirectory.GetFiles())

            {

                webForScripting.Document.InvokeScript("PrintFileName", new string[] {curFileToPrint.Name});

                //tbxResults.AppendText(curFileToPrint.Name + "\r\n");

            }

        }

נריץ את האפליקציה ונבחר את כונן C.

אז מה יש לנו כאן?

קוד ג'אווה סקריפט שקורא למתודה בדוט-נט,
וקוד בדוט-נט שקורא לקוד ג'אווה סקריפט.

 

הקוד שעבדנו עליו זמין להורדה כאן - http://www.JustinAngel.Net/files/Blog-JavaScriptWinformsInterop.zip.

Published Tuesday, June 05, 2007 11:48 AM by Justin-Josef Angel [MVP]

Comments

No Comments