FileOpenDialog Extension for CSHTML5

JS-Support
Site Admin
Posts: 678
Joined: Tue Apr 08, 2014 3:42 pm

FileOpenDialog Extension for CSHTML5

Postby JS-Support » Fri Mar 04, 2016 10:36 am

Dear CSHTML5 users,

I am pleased to inform you of the release of the FileOpenDialog Extension for CSHTML5.


It adds the ability to let the user pick a file using the "Open File..." dialog of the browser.

It can also be used for example in conjunction with the ZipFile Extension to load a ZIP file. Note: if you are looking for a way to save files to disk, you can use the FileSaver Extension.


It requires CSHTML5 v1.0 Beta 7.2 or newer.


To use, simply add a new class named "FileOpenDialog.cs" to your project, and copy/paste the following code:

Code: Select all

using System;
using System.Collections.Generic;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

//------------------------------------
// This is an extension for C#/XAML for HTML5 (www.cshtml5.com)
//
// It requires Beta 7.2 or newer.
//
// It adds the ability to let the user pick a file using the
// "Open File..." dialog of the browser.
//
// It can also be used for example in conjunction with the ZipFile
// Extension to load a ZIP file. Note: if you are looking for
// a way to save files to disk, you can use the FileSaver Extension.
//
// The extension works by adding an <input type='file'> tag to the
// HTML DOM, which will cause the "Open file..." dialog to appear,
// and by listening to its "change" event in order to get a reference
// to the selected file. it returns a JavaScript blob. If the file
// is a plain text file, it will also return a string with the text
// content of the file.
//
// This extension is licensed under the open-source MIT license:
// https://opensource.org/licenses/MIT
//
// Copyright 2016 Userware / CSHTML5
//------------------------------------

namespace CSHTML5.Extensions.FileOpenDialog
{
    public class ControlForDisplayingTheFileOpenDialog : Control
    {
        public event EventHandler<FileOpenedEventArgs> FileOpened;

        public ControlForDisplayingTheFileOpenDialog()
        {
            CSharpXamlForHtml5.DomManagement.SetHtmlRepresentation(this,
                "<input type='file'>");

            this.Loaded += ControlForDisplayingAFileOpenDialog_Loaded;
        }

        void ControlForDisplayingAFileOpenDialog_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e)
        {
            // Get the reference to the "input" element:
            var inputElement = CSHTML5.Interop.GetDiv(this);

            Action<object, string> onFileOpened = (jsBlob, plainTextContentIfAny) =>
                {
                    if (this.FileOpened != null)
                        this.FileOpened(this, new FileOpenedEventArgs(jsBlob, plainTextContentIfAny));
                };

            // Apply the "Filter" property to limit the choice of the user to the specified extensions:
            SetFilter(this.Filter);

            // Listen to the "change" property of the "input" element, and call the callback:
            CSHTML5.Interop.ExecuteJavaScript(@"
                $0.addEventListener(""change"", function(evt){
                    var input = event.target;
                    var file = input.files[0];
                    var reader = new FileReader();
                    reader.onload = function(){
                      var callback = $1;
                      var plainTextContentIfAny = '';
                      var jsBlob = reader.result;
                      if (file.type == 'text/plain'){
                        plainTextContentIfAny = reader.result;
                      }
                      callback(jsBlob, plainTextContentIfAny);
                    };
                    reader.readAsText(file);
                    var isRunningInTheSimulator = $2;
                    if (isRunningInTheSimulator)
                        alert(""The file open dialog is not supported in the Simulator. Please test in the browser instead."");
                });", inputElement, onFileOpened, CSHTML5.Interop.IsRunningInTheSimulator);
        }

        void SetFilter(string filter)
        {
            // Get the reference to the "input" element:
            var inputElement = CSHTML5.Interop.GetDiv(this);

            // Process the filter list to convert the syntax from XAML to HTML5:
            // Example of syntax in Silverlight: Image Files (*.bmp, *.jpg)|*.bmp;*.jpg|All Files (*.*)|*.*
            // Example of syntax in HTML5: .gif, .jpg, .png, .doc
            string[] splitted = filter.Split('|');
            List<string> itemsKept = new List<string>();
            if (splitted.Length == 1)
            {
                itemsKept.Add(splitted[0]);
            }
            else
            {
                for (int i = 1; i < splitted.Length; i += 2)
                {
                    itemsKept.Add(splitted[i]);
                }
            }
            string filtersInHtml5 = String.Join(",", itemsKept).Replace("*", "").Replace(";", ",");

            // Apply the filter:
            if (!string.IsNullOrWhiteSpace(filtersInHtml5))
            {
                CSHTML5.Interop.ExecuteJavaScript(@"$0.accept = $1", inputElement, filtersInHtml5);
            }
            else
            {
                CSHTML5.Interop.ExecuteJavaScript(@"$0.accept = """"", inputElement);
            }
        }


        public string Filter
        {
            get { return (string)GetValue(FilterProperty); }
            set { SetValue(FilterProperty, value); }
        }
        public static readonly DependencyProperty FilterProperty =
            DependencyProperty.Register("Filter", typeof(string), typeof(ControlForDisplayingTheFileOpenDialog), new PropertyMetadata("", Filter_Changed));

        static void Filter_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var control = (ControlForDisplayingTheFileOpenDialog)d;
            if (CSharpXamlForHtml5.DomManagement.IsControlInVisualTree(control))
            {
                control.SetFilter((e.NewValue ?? "").ToString());
            }
        }
    }

    public class FileOpenedEventArgs : EventArgs
    {
        /// <summary>
        /// Only available if file is of type Plain Text.
        /// </summary>
        public readonly string PlainTextContent;

        public readonly object JavaScriptBlob;

        public FileOpenedEventArgs(object javaScriptBlob, string plainTextContentIfAny)
        {
            this.JavaScriptBlob = javaScriptBlob;
            this.PlainTextContent = plainTextContentIfAny;
        }
    }
}



The extension works by adding an <input type='file'> tag to the HTML DOM, which will cause the "Open file..." dialog to appear, and by listening to its "change" event in order to get a reference to the selected file. it returns a JavaScript blob. If the file is a plain text file, it will also return a string with the text content of the file.


To use the code:
- Add the following control to your XAML:

Code: Select all

<Page
    ...
    xmlns:extensions="using:CSHTML5.Extensions.FileOpenDialog"
    ...
>
    <Canvas>
        <extensions:ControlForDisplayingTheFileOpenDialog FileOpened="OnFileOpened" Filter="*.txt,*.csv"/>
    </Canvas>
</Page>

- Add the following code to your C# (code-behind):

Code: Select all

async void OnFileOpened(object sender, CSHTML5.Extensions.FileOpenDialog.FileOpenedEventArgs e)
{
    MessageBox.Show(e.PlainTextContent);
}


For security reason, the user needs to click the control in order for the Open File Dialog to appear.

You can also see an example of use with binary content by looking at the ZipFile Extension.

Regards,
JS-Support

rkmore
Posts: 49
Joined: Mon Dec 07, 2015 1:53 pm

Accessing the camera

Postby rkmore » Mon Apr 04, 2016 4:53 am

To access the camera using this extension change:

Code: Select all

            CSharpXamlForHtml5.DomManagement.SetHtmlRepresentation(this,
                "<input type='file'>");


to

Code: Select all

            CSharpXamlForHtml5.DomManagement.SetHtmlRepresentation(this,
                "<input type='file' accept='image/*' capture='camera'>");


RKM

JS-Support
Site Admin
Posts: 678
Joined: Tue Apr 08, 2014 3:42 pm

Re: FileOpenDialog Extension for CSHTML5

Postby JS-Support » Mon Apr 04, 2016 9:06 am

Thanks a lot RKM for your contribution.


Return to “Extensions and Plugins for CSHTML5”

Who is online

Users browsing this forum: No registered users and 1 guest