locked
How to get a full file path in a SaveFileDialog? RRS feed

  • Question

  • Hello,

    In my Silverlight application I am trying to save a file on the local computer.

    For this, in MainPage I am using a  SaveFileDialog and the string address I am sendinding to the WCF service and there the file is saving.

    A problem is, that by SaveFileDialog I can get only the file name, without full file path. Plus to this, there is no InitialDirectory property to the SaveFileDialog. How can I solve the problem?

    Here is the code:

      SaveFileDialog sfd = new SaveFileDialog();
                sfd.Filter = "Xml files (*.xml)|*.xml";
                sfd.ShowDialog();
                string saveFileName = sfd.SafeFileName;
                ServiceReference1.SavePointsFileAsync(saveFileName);
    Thanks.
    Friday, October 21, 2011 9:01 AM

Answers

  • The reason I wanted to send the full file path to the WCF service, was a fact that the file exists on the server side, so from WCF would be simpler to get it.

    I'm even confused now.  What file exists on the server side?

    If you mean there is a file exists on the server side and you want to download it then save it to the client side, why do you need to pass the file path to the server? This file path is for the file to be saved on the client, it has nothing to do with the exiting file on your server.

    Here is the code for the server (WCF) side:

    public void SavePointsFile()
            {
                SaveFileDialog sfd = new SaveFileDialog();
                sfd.FileName = "FileName.xml";
                sfd.DefaultExt = "*.xml";
                sfd.Filter = "Xml files (*.xml)|*.xml";
                sfd.ShowDialog();
                XmlDocument pdoc = new XmlDocument();
                pdoc.Load(HostingEnvironment.MapPath("~/Resources/Points.xml"));
                pdoc.Save(sfd.FileName);
            }

    Why do you need a SaveFileDialog on your Service code?  Your server side code is running as Service on your server, not a Window's UI program.  It doesn't have any UI to take user's interaction.  How can SaveFileDialog work there? SaveFileDialog always requires user interaction. When the Dialog popups up, user needs to select a file path then click "OK" or "Cancel" button in order for the process to continue. There won't be an user on your Server to take this action. 

    I just don't understand what you are really trying to do by reading your code. Maybe you should tell us what you want to achieve so we can help you.

    Are you trying to download a file from your server and save it to the Client machine by using a SaveFileDialog? If yes, the code should be like this:

    private void Button_Click(object sender, RoutedEventArgs e)
            {
    string fileName ="Test.xml"; // Assume this is the file name on your server you want to download and save

               SaveFileDialog sfd = new SaveFileDialog();
             
     sfd.GetType().GetMethod("set_DefaultFileName").Invoke(sfd, new object[] { fileName });// code for Silverlight 4 to set initial file name

     sfd.DefaultFileName = fileName; //code for Silverlight 5 to set initial file name

               sfd.DefaultExt = "*.xml";
               sfd.Filter = "Xml files (*.xml)|*.xml";
               if(sfd.ShowDialog() == true)
               {
                  WebClient client = new WebClient();
                  client.OpenReadCompleted += new    OpenReadCompletedEventHandler(client_OpenReadCompleted);
                  client.OpenReadAsync(new Uri("../" + fileName, UriKind.Relative), sfd); //assume the file is under your Web project        
               }
            }

            void client_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
            {
                Stream inputStream = e.Result;
                StreamReader reader = new StreamReader(inputStream);
                SaveFileDialog sfd = e.UserState as SaveFileDialog;
                var writer = new StreamWriter(sfd.OpenFile());
                writer.Write(reader.ReadToEnd());
                inputStream.Close();
                reader.Close();                        
                writer.Close();
                MessageBox.Show("File is Saved");
            }      



    Saturday, October 22, 2011 9:20 PM
  • Sally, THanks one more time. Finally your code:

    sfd.GetType().GetMethod("set_DefaultFileName").Invoke(sfd, new object[] { "GraphPoints.xml" });
    sfd.DefaultFileName = fileName;

    works on my computer. You should say it's for SL5 at your first answer.

    My fault was that I forgot to say the file exists on the server side (in my first letter, I did it in my second ones).

    Thanks a lot,

    LeonidZ.

    P.S.

    And all this only for one little thing: the client could see the default file name with SaveFileDialod opening :-)

    Monday, October 24, 2011 3:39 PM

All replies

  • Friday, October 21, 2011 10:05 AM
  • SaveFileDialog sfd = new SaveFileDialog();

    sfd.Filter = "Xml files (*.xml)|*.xml"; sfd.ShowDialog();

    string saveFileName = sfd.SafeFileName;

    ServiceReference1.SavePointsFileAsync(saveFileName);

    I'm confused reading your code. Where do you want to save this file? Looks like you are trying to call some Web Service by passing this file name (the last line of your code) to server. Are you trying to save the file to your Server or to the Client machine?

    SaveFileDialog is for you to save some content to a file on Client machine.  sfd.ShowDialog() should open a Dialog so user can select a folder (on their machine) and enter a file name, then the content can be written out to that File.

    Usually the code to write out the file is like this:

                SaveFileDialog dialog = new SaveFileDialog();         

                // You can use this line to set the initial FileName:
                dialog.GetType().GetMethod("set_DefaultFileName").Invoke(dialog, new object[] { "SomeFileName.xml" });


                dialog.DefaultExt = "*.xml";
                dialog.Filter = "Excel Xml (*.xml)|*.xml|All files (*.*)|*.*";
                if (dialog.ShowDialog() == true)
                {         
                    string xml = YourXMLString;
                    Steam fileStream  =  dialog.OpenFile(); // Get the file stream to do output
                    var writer = XmlWriter.Create(fileStream);
                    writer.WriteRaw(xml);
                    writer.Close();               
                    MessageBox.Show("File is Saved");
                }

    If you want to save content to a File back to Server, you don't need to use FileSaveDialog. If the content is already in memory, you can call a Web Service to send the content back to save it anywhere you want on your server.

    If you want to upload a file from client machine back to server, you use FileOpenDialog to have user to select the file,  read the content from that file then use a Web Service to send the content back to server.

    Friday, October 21, 2011 10:31 AM
  • SaveFileDialog sfd = new SaveFileDialog();

    sfd.Filter = "Xml files (*.xml)|*.xml";

    sfd.ShowDialog();

    string saveFileName = sfd.SafeFileName;

    ServiceReference1.SavePointsFileAsync(saveFileName);

    I'm confused reading your code. Where do you want to save this file? Looks like you are trying to call some Web Service by passing this file name (the last line of your code) to server. Are you trying to save the file to your Server or to the Client machine?

    SaveFileDialog is for you to save some content to a file on Client machine.  sfd.ShowDialog() should open a Dialog so user can select a folder (on their machine) and enter a file name, the content can be written out to that File.

    Usually the code to write out the file is like this:

                SaveFileDialog dialog = new SaveFileDialog();         

                // You can use this line to set the initial FileName:
                dialog.GetType().GetMethod("set_DefaultFileName").Invoke(dialog, new object[] { "SomeFileName.xml" });


                dialog.DefaultExt = "*.xml";
                dialog.Filter = "Excel Xml (*.xml)|*.xml|All files (*.*)|*.*";
                if (dialog.ShowDialog() == true)
                {         
                    string xml = YourXMLString;
                    Steam fileStream  =  dialog.OpenFile();
                    var writer = XmlWriter.Create(fileStream);
                    writer.WriteRaw(xml);
                    writer.Close();               
                    MessageBox.Show("File is Saved");
                }

    If you want to save content to a File back to Server, you don't need to use FileSaveDialog. If the content is already in memory, you can call a Web Service to send the content back to save it anywhere you want on your server.

    If you want to upload a file from client machine back to server, you use FileOpenDialog to have user to select the file,  read the content from that file then use a Web Service to send the content back to server.

    Friday, October 21, 2011 10:37 AM
  • I believe he wants to save the file locally and then send the file's full path back to the server.

    Friday, October 21, 2011 12:03 PM
  • Hello,

    Thanks for your cooperation.

    The reason I wanted to send the full file path to the WCF service, was a fact that the file exists on
    the server side, so from WCF would be simpler to get it.

    Since it’s impossible (for security reasons), I had to organize WEB client on the client side.

    Here is the working code (needs the client side only):

    private void Button1_Click(object sender, RoutedEventArgs e)
    {
       SaveFileDialog sfd = new SaveFileDialog();
       sfd.ShowDialog();
       sfd.DefaultExt = "*.xml";
       sfd.Filter = "Xml files (*.xml)|*.xml";
       sfd.ShowDialog();
       WebClient client = new WebClient();
       client.OpenReadCompleted += new  OpenReadCompletedEventHandler(client_OpenReadCompleted);
       client.OpenReadAsync(new Uri("FileToSave.xml", UriKind.Relative)); //In this case FileToSave.xml" exists in the     "ClientBin" folder        
    }
    void client_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
    {
       XElement xml = XElement.Load(XmlReader.Create(e.Result));
       Stream fileStream = sfd.OpenFile();
       var writer = XmlWriter.Create(fileStream);
       xml.Save(writer);
       writer.Close();
       fileStream.Close();
       MessageBox.Show("File is Saved");
    }
    

    (based on: http://channel9.msdn.com/Blogs/mtaulty/Silverlight-ReadingWriting-XML)

     Unfortunately, in the Silverlight Client Side there are missing properties like FileName etc. for the SaveFileDialog.

    To the contrary, in WCF there is a complete case of properties for the SaveFileDialog (with “using System.Windows.Forms”). I tried it. Here is the code for the client side:

    private void Button1_Click(object sender, RoutedEventArgs e)
    {
       ServiceReference1.ServerSideFunctionAsync();
    }
    

    Here is the code (not working) for the server (WCF) side:

    public void Service1Function()
            {
                SaveFileDialog sfd = new SaveFileDialog();
                sfd.FileName = "DefaultFileName.xml";
                sfd.DefaultExt = "*.xml";
                sfd.Filter = "Xml files (*.xml)|*.xml";
                sfd.ShowDialog();
                XmlDocument pdoc = new XmlDocument();
                pdoc.Load(HostingEnvironment.MapPath("~/Resources/FileName.xml"));
                pdoc.Save(sfd.UserFileName);
            }
    

    There is a problem with this code: it stops on  sfd.ShowDialog(); and appears exception: ” Current thread must be set to single
    thread apartment (STA) mode before OLE calls can be made. Ensure that your Main
    function has STAThreadAttribute marked on it.”

    Do you know what's a problem?

    Thanks.

    Saturday, October 22, 2011 4:13 PM
  • Hello,

    Thanks for your cooperation.

    The reason I wanted to send the full file path to the WCF service, was a fact that the file exists on the server side, so from WCF would be simpler to get it.

    Since it’s not possible for security reasons, I had to organize WEB client on the client side.

    Here is the working code (needs the client side only):

     

    private void Button1_Click(object sender, RoutedEventArgs e)
    {
       SaveFileDialog sfd = new SaveFileDialog();
       sfd.ShowDialog();
       sfd.DefaultExt = "*.xml";
       sfd.Filter = "Xml files (*.xml)|*.xml";
       sfd.ShowDialog();
       WebClient client = new WebClient();
       client.OpenReadCompleted += new    OpenReadCompletedEventHandler(client_OpenReadCompleted);
       client.OpenReadAsync(new Uri("FileToSave.xml", UriKind.Relative)); //In this case FileToSave.xml" exists in the "ClientBin" folder        
    }
    void client_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
    {
       XElement xml = XElement.Load(XmlReader.Create(e.Result));
       Stream fileStream = sfd.OpenFile();
       var writer = XmlWriter.Create(fileStream);
       xml.Save(writer);
       writer.Close();
       fileStream.Close();
       MessageBox.Show("File is Saved");
    }
    

    (based on: http://channel9.msdn.com/Blogs/mtaulty/Silverlight-ReadingWriting-XML)

     Unfortunately, in the Silverlight Client Side there are missing properties like FileName etc. for the SaveFileDialog.

    To the contrary, in WCF there is a complete case of properties for the SaveFileDialog (with “using
    System.Windows.Forms”). I tried it. Here is the code for the client side:

    private void Button1_Click(object sender, RoutedEventArgs e)
    { 
       ServiceReference1.SavePointsFileAsync();
    }
    

    Here is the code for the server (WCF) side:

     

    public void SavePointsFile()
            {
                SaveFileDialog sfd = new SaveFileDialog();
                sfd.FileName = "FileName.xml";
                sfd.DefaultExt = "*.xml";
                sfd.Filter = "Xml files (*.xml)|*.xml";
                sfd.ShowDialog();
                XmlDocument pdoc = new XmlDocument();
                pdoc.Load(HostingEnvironment.MapPath("~/Resources/Points.xml"));
                pdoc.Save(sfd.FileName);
            }
    

    There is a
    problem with this code: appears exception: ” Current thread must be set to single
    thread apartment (STA) mode before OLE calls can be made. Ensure that your Main
    function has STAThreadAttribute marked on it.”

    Do you
    know what’s a problem?

    Thanks.

    Saturday, October 22, 2011 4:26 PM
  • The reason I wanted to send the full file path to the WCF service, was a fact that the file exists on the server side, so from WCF would be simpler to get it.

    I'm even confused now.  What file exists on the server side?

    If you mean there is a file exists on the server side and you want to download it then save it to the client side, why do you need to pass the file path to the server? This file path is for the file to be saved on the client, it has nothing to do with the exiting file on your server.

    Here is the code for the server (WCF) side:

    public void SavePointsFile()
            {
                SaveFileDialog sfd = new SaveFileDialog();
                sfd.FileName = "FileName.xml";
                sfd.DefaultExt = "*.xml";
                sfd.Filter = "Xml files (*.xml)|*.xml";
                sfd.ShowDialog();
                XmlDocument pdoc = new XmlDocument();
                pdoc.Load(HostingEnvironment.MapPath("~/Resources/Points.xml"));
                pdoc.Save(sfd.FileName);
            }

    Why do you need a SaveFileDialog on your Service code?  Your server side code is running as Service on your server, not a Window's UI program.  It doesn't have any UI to take user's interaction.  How can SaveFileDialog work there? SaveFileDialog always requires user interaction. When the Dialog popups up, user needs to select a file path then click "OK" or "Cancel" button in order for the process to continue. There won't be an user on your Server to take this action. 

    I just don't understand what you are really trying to do by reading your code. Maybe you should tell us what you want to achieve so we can help you.

    Are you trying to download a file from your server and save it to the Client machine by using a SaveFileDialog? If yes, the code should be like this:

    private void Button_Click(object sender, RoutedEventArgs e)
            {
    string fileName ="Test.xml"; // Assume this is the file name on your server you want to download and save

               SaveFileDialog sfd = new SaveFileDialog();
             
     sfd.GetType().GetMethod("set_DefaultFileName").Invoke(sfd, new object[] { fileName });// code for Silverlight 4 to set initial file name

     sfd.DefaultFileName = fileName; //code for Silverlight 5 to set initial file name

               sfd.DefaultExt = "*.xml";
               sfd.Filter = "Xml files (*.xml)|*.xml";
               if(sfd.ShowDialog() == true)
               {
                  WebClient client = new WebClient();
                  client.OpenReadCompleted += new    OpenReadCompletedEventHandler(client_OpenReadCompleted);
                  client.OpenReadAsync(new Uri("../" + fileName, UriKind.Relative), sfd); //assume the file is under your Web project        
               }
            }

            void client_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
            {
                Stream inputStream = e.Result;
                StreamReader reader = new StreamReader(inputStream);
                SaveFileDialog sfd = e.UserState as SaveFileDialog;
                var writer = new StreamWriter(sfd.OpenFile());
                writer.Write(reader.ReadToEnd());
                inputStream.Close();
                reader.Close();                        
                writer.Close();
                MessageBox.Show("File is Saved");
            }      



    Saturday, October 22, 2011 9:20 PM
  • As someone pointed out before, this can be done in SL4 due to security reasons. But there are ways to accomplish this with elevated trust, Out of Browser and with COM. Is this a viable option for your project?

    Sunday, October 23, 2011 8:18 PM
  • Sally, THanks one more time. Finally your code:

    sfd.GetType().GetMethod("set_DefaultFileName").Invoke(sfd, new object[] { "GraphPoints.xml" });
    sfd.DefaultFileName = fileName;

    works on my computer. You should say it's for SL5 at your first answer.

    My fault was that I forgot to say the file exists on the server side (in my first letter, I did it in my second ones).

    Thanks a lot,

    LeonidZ.

    P.S.

    And all this only for one little thing: the client could see the default file name with SaveFileDialod opening :-)

    Monday, October 24, 2011 3:39 PM
  • You don't need both lines there.

    Use this line if your project target version is Silverlight 4:

    sfd.GetType().GetMethod("set_DefaultFileName").Invoke(sfd, new object[] { "GraphPoints.xml" }); //This line works in Silverlight 4.

    Use line line if your project target version is Silverlight 5:

    sfd.DefaultFileName = fileName; // Works in Silverlight 5

    Monday, October 24, 2011 3:58 PM
  • Sorry sladapter, no pun intended, there isn't a "set_DefaultFileName" on SL4. May you specify the exact SL version (XX.XX.XXXX.XXXX)? 
     
    Please run the code below.
    this.fileDialog = new SaveFileDialog();
                
                var methods = this.fileDialog.GetType().GetMethods();
                string m = string.Empty;
    
                foreach (var item in methods)
                {
                    m += item.Name + "\n";
                }
                MessageBox.Show(m);
    Monday, October 24, 2011 4:27 PM
  • I'm running in Silverlight 5 (5.0.60818.0) runtime. The Project target is Silverlight 4. It might only work in Silverlight 5 Run time. 

    Monday, October 24, 2011 4:49 PM