Click here to Skip to main content
15,881,248 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I have a C# program. I'm watching a directory for changes to an xml file, and when the file changes I want to ready the xml and update a rich textbox.
It all works when I specify the file. It reads it and populates the RTB fine. But when I add code to try to do it automatically when the files changes I get the error

Error 1 An object reference is required for the non-static field, method, or property 'xml_reader.Form1.readXML(string)'

I've read several examples on this but I still don't get it.

this fires when it should
C#
private static void OnChanged(object source, FileSystemEventArgs e)
 {
     // Specify what is done when a file is changed, created, or deleted.
     string path = e.FullPath;
     Console.WriteLine("File: " + path + " " + e.ChangeType);
    readXML(path);
 }


I want to call
C#
private void readXML(string Filename)
{
    int linenumbers = 0;
    string stringvalue;
    string stringname;
    String title = "POS           PILOT                 LAPS    ELAPSED      SEED         FAST LAP \n";
    richTextBox1.Text = title;
    XmlTextReader reader = new XmlTextReader(Filename);
    while (reader.Read())
    {
        switch (reader.NodeType)
        {
            case XmlNodeType.Element: // The node is an element.
                if (reader.Name == "Driver")
                {

                    while (reader.MoveToNextAttribute()) // Read the attributes.
                    {
                        stringvalue = reader.Value;
                        stringname = reader.Name;
                        if (stringname == "position")
                        {
                            richTextBox1.Text += (" " + stringvalue + "\t");
                        }
                        if (stringname == "name")
                        {
                            string longname = stringvalue;
                            longname = longname.PadRight(30);
                            int namelength = longname.Length;
                            Console.WriteLine(longname + namelength);
                            richTextBox1.Text += (longname);
                        }
                        if (stringname == "laps")
                        {
                            if (stringvalue == " ")
                                stringvalue = "0";
                            richTextBox1.Text += ("  " + stringvalue + "\t\t");
                        }
                        if (stringname == "seed")
                        {
                            if (stringvalue == " ")
                                stringvalue = "0.000";
                            richTextBox1.Text += (stringvalue + "\t\t");
                        }
                        if (stringname == "elapsedTime")
                        {
                            if (stringvalue == " ")
                                stringvalue = "0.000";
                            richTextBox1.Text += (" " + stringvalue + "\t\t");
                        }
                        if (stringname == "fastLap")
                        {
                            if (stringvalue == " ")
                                stringvalue = "0.000";
                            stringvalue = stringvalue.PadRight(8);
                            richTextBox1.Text += (" " + stringvalue + Environment.NewLine);
                            linenumbers++;
                        }
                    }
                }
                break;
            case XmlNodeType.Text: //Display the text in each element.
                break;
            case XmlNodeType.EndElement: //Display the end of the element.
                break;
        }
    }
    reader.Close();
    colorTextbox(linenumbers);
}



If I change the function so that it is "static void readXML(string Filename)"
then I get errors on richtextbox1.

What is the easiest way to fix it?
Thanks in advance.

What I have tried:

making the called routine static.
Posted
Updated 16-Jun-16 14:40pm
Comments
Matt T Heffron 16-Jun-16 16:52pm    
Try removing the static from the OnChanged method.

A method should be static if you simply don't need "this", which is the reference to the instance of some class. This "this" is an implicit method which is passed to all instance methods. (This way, "instance method" is antonym to "static method".) You only can call an instance method on some instance (instanceName.MethodName(/* … */)) and you can only call static method on the type (TypeName.MethodName(/* … */)), so that instance becomes the reference to the instance passed to an instance method.

You can access all type members through "this", and, therefore, from a static method you can only access static member. Using static methods, in practice, is a must when you have methods unrelated to other members, such as some mathematical calculations only operating with parameters.

For some more detail, please see my past answers:
Type casting in c#,
C# windows base this key word related and its uses in the application,
What makes static methods accessible?.

Using a static method as some event handler is possible, but it is extremely unlikely to turn out useful. That explains the comment to the question by Matt T Heffron.

—SA
 
Share this answer
 
v2
Comments
Matt T Heffron 17-Jun-16 12:41pm    
+5 to counter undeserved 1 vote.
Sergey Alexandrovich Kryukov 17-Jun-16 15:04pm    
Thank you, Matt.
—SA
Afzaal Ahmad Zeeshan 17-Jun-16 15:04pm    
5ed; just saying, types in C# have all caps as TypeName. ;-) But that doesn't matter, a good answer.
Sergey Alexandrovich Kryukov 17-Jun-16 15:06pm    
Thank you, Afzaal.
Do you mean Microsoft naming conventions? You are right, this is what I meant to write; I'll fix it — thank you for the correction.
—SA
In addition to my comment above about making the OnChanged method not be static, there are other things very wrong with your code. Not the least of which is the abuse of string concatenation! You should use StringBuilder Class (System.Text)[^]:
C#
private void readXML(string Filename)
{
  int linenumbers = 0;
  string stringvalue;
  const string title = "POS           PILOT                 LAPS    ELAPSED      SEED         FAST LAP \n";
  StringBuilder builder = new StringBuilder(title, 1024); // 1k is a fair starting "guess" ;-)
  using (XmlTextReader reader = new XmlTextReader(Filename))
  {
    // The using statement ensures that reader is Closed when done.
    while (reader.Read())
    {
      switch (reader.NodeType)
      {
      case XmlNodeType.Element: // The node is an element.
        if (reader.Name == "Driver")
        {
          while (reader.MoveToNextAttribute()) // Read the attributes.
          {
            stringvalue = reader.Value;
            switch (reader.Name)
            {
            case "position":
              builder.Append(" ").Append(stringvalue).Append("\t");
              break;
            case "name":
              string longname = stringvalue.PadRight(30);
              Console.WriteLine("{0} {1}", longname, longname.Length);
              builder.Append(longname);
              break;
            case "laps":
              if (string.IsNullOrWhiteSpace(stringvalue))
                stringvalue = "0";
              builder.Append("  ").Append(stringvalue).Append("\t\t");
              break;
            case "seed":
              if (string.IsNullOrWhiteSpace(stringvalue))
                stringvalue = "0.000";
              builder.Append(stringvalue).Append("\t\t");
              break;
            case "elapsedTime":
              if (string.IsNullOrWhiteSpace(stringvalue))
                stringvalue = "0.000";
              builder.Append(" ").Append(stringvalue).Append("\t\t");
              break;
            case "fastLap":
              if (string.IsNullOrWhiteSpace(stringvalue))
                stringvalue = "0.000";
              stringvalue = stringvalue.PadRight(8);
              builder.Append(" ").AppendLine(stringvalue);
              linenumbers++;
              break;
            default:
              break;
            }
          }
        }
        break;
      case XmlNodeType.Text: //Display the text in each element.
        break;
      case XmlNodeType.EndElement: //Display the end of the element.
        break;
      }
    }
  }
  // Edit: Matt Heffron: 6/17/2016
  // Dealing with the Cross-thread access error:
  // Was:
  richTextBox1.Text = builder.ToString();
  // Change to:
  Action updateText = () => richTextBox1.Text = builder.ToString();
  if (richTextBox1.InvokeRequired)
    richTextBox1.Invoke(updateText);
  else
    updateText();
  // End of Edit
  colorTextbox(linenumbers);
}

In addition, tabular data like this would be better presented using a DataGrid control instead of a RichTextBox.
 
Share this answer
 
v4
Comments
Sergey Alexandrovich Kryukov 16-Jun-16 20:43pm    
I voted 4 this time. You have some very good points, but static vs instance methods are not explained.
Yes, I know, it's extremely difficult to explain the fundamentals in brief, especially to people who try to do something advanced without understanding of the basics. This is the main problem of most of out inquirers, isn't it.

I tried to explain it in Solution 2, crediting your comment to the question.

—SA
Member 3652617 17-Jun-16 11:09am    
Thanks Matt, I will definitely look at the data grid.I made the string changes you posted. When I remove static from the Onchange method, I then get an error on the line
richTextBox1.Text = builder.ToString();
I'm assuming I would get the same error if it were a data grid. The error is
An unhandled exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll

Additional information: Cross-thread operation not valid: Control 'richTextBox1' accessed from a thread other than the thread it was created on.

Its probably what Sergey tried to explain below but it went over my head. I'm obviously not a programmer. Thanks for explaining it and I'll read it a few more times, but can you help me with this error as well please. Thanks Again.
Matt T Heffron 17-Jun-16 12:41pm    
The Cross-thread error is because you are executing this in a different thread from the UI thread. The properties/methods of UI controls must be access from the UI thread. There a property and a method on controls to deal with this.
See my update to the Solution.
If the colorTextbox method (or any method) accesses any UI controls from a thread other than the UI thread then this same error will occur there. You'll need to look for and fix all of these!
Member 3652617 17-Jun-16 12:59pm    
Thanks, I couldn't get it to run with the line
Action updateText = () => {richTextBox1.Text = builder.ToString();}
so I took out the brakets and made it
Action updateText = () => richTextBox1.Text = builder.ToString();
not sure if that broke it or not, but now the error is
on line while(reader.Read())
and its An unhandled exception of type 'System.IO.IOException' occurred in System.Xml.dll

Additional information: The process cannot access the file 'C:\Users\ldavis\Dropbox\RC\DRC\xml\driverData.xml' because it is being used by another process.
Matt T Heffron 17-Jun-16 14:49pm    
Actually all you needed was a ; after the } (oops!)
The IOException means that some other process has that file open, probably for writing. Since you are calling this because of a FileWatcher Changed event, you need to wait for a little time after the "last" Changed event to determine if the file is done changing and is "readable". How long depends on how the file is being written.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900