• Welcome to Valhalla Legends Archive.
 

C# Basic Question

Started by Noodlez, October 16, 2007, 02:25 AM

Previous topic - Next topic

Noodlez

Expected: Basic answer.

Within a form I have a function (AddChat) and a class being threaded operating listening sockets, the thread needs to call the AddChat function. To invoke it sure that sounds reasonable, however the class doesn't have access to the AddChat function (why?! It's public!Q.)

Suggestions. Go. Need to see my code? Tell me.

K

Sounds like you are trying to reference the function via the form's class name, not the instance.  You need to pass a reference to the form to your class or function or find a reference to the form in some other way.

Chriso

#2
Heres how I did it for my bot that I'm working on...

This is what goes into the Form that the RichTextBox belongs to...

        // determine whether to invoke
        public void AddChat(object[] obj)
        {
            Connection.AddChatCallback ac = new Connection.AddChatCallback(AddChatImpl);
            if (rtbChat.InvokeRequired)
            {
                rtbChat.Invoke(ac, new object[] { obj });
            }
            else
            {
                ac(obj);
            }
        }
        // routine to add time and text array to rtb...
        public void AddChatImpl(object[] obj)
        {
            if (lockBufferToolStripMenuItem.Checked) { return; }
            try
            {
                rtbChat.SelectionStart = rtbChat.Text.Length;
                rtbChat.SelectionColor = Color.DimGray;
                rtbChat.SelectedText = "[" + DateTime.Now.ToLongTimeString() + "] ";
                int n = 2;
                for (int i = obj.GetLowerBound(0); i < (obj.GetUpperBound(0) + 1); i += n)
                {
                    rtbChat.SelectionStart = rtbChat.Text.Length;
                    rtbChat.SelectionColor = (Color)obj[i];
                    rtbChat.SelectedText = obj[i + 1].ToString();
                }
                rtbChat.SelectionStart = rtbChat.Text.Length;
                rtbChat.SelectedText = "\n";
                rtbChat.SelectionLength = 0;
                rtbChat.ScrollToCaret();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error: " + ex.Message);
            }
        }


Then this goes in my "Connection" class:

        public delegate void AddChatCallback(object[] obj);   // Used within main form
        public delegate void Output(params object[] obj);      // Enables Color, Text, Color, Text, etc...

        public Output AddChat = null;


To initialize "AddChat" (within the connection class) you simply do something along the lines of this within the Form containing the RichTextBox:

        Connection c = new Connection();
        c.AddChat = new Connection.Output(AddChat);


Criticism welcome, I'm new to C# :-)

PS: I suggest you read up on "delegates" and "events" they are a lifesaver for multi-threaded applications...

MyndFyre

This isn't so much a "C#" problem as much as an "object-oriented programming" problem.

C# is an object-oriented language.  There's no getting around that truth, and with that in mind, you should endeavor to use the tools C# gives you to make using it a bit easier.  C# isn't like Visual Basic, in that there's not just a form with some controls on it and you can access the controls by name. 

Everything in C# is centered around objects.  An object is a conceptual unit of division; in programming, an object has state, has behavior, and has a unique identity.  In C#, we define state and behavior within a class; an object's identity is based on its memory location.  Specifically, when you give a class its fields, you're assigning it state; when you give a class methods, you're giving it behavior.  When you call new SomeObject();, you're setting aside a region of memory that becomes that object's identity.

When you want to add text to a rich text box, for example, you call methods on it (properties are really methods that look like fields).  There is an instance of a rich textbox on your form, and it has behaviors.  Similarly, your form is an object, and it has an identity.  You have to pass that identity to other objects that need to use it.

A variable in code has two pieces of information: type and identity.  For instance, in Chriso's code, "rtbChat" is a variable that is typed RichTextBox and has its own memory space.  RichTextBox defines its state and behavior - for example, Chriso can set the SelectionStart and SelectionColor attributes.

Keep this in mind when you're trying to develop in C#.  It's a very different beast than Visual Basic.
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

Chriso


Joe[x86]

For the invoking itself, check out this class I wrote when I made FelBot. It's a bit overly commented but that never hurt anyone.

The reason C# makes you invoke instead of directly accessing the properties directly is to eliminate the possibility of a race condition, since the two methods can be operating at the same time if they're in different threads. Invoking tells the thread of the object you're invoking on to call back to a delegate with certain arguments, and that method is executed in that thread.
Quote from: brew on April 25, 2007, 07:33 PM
that made me feel like a total idiot. this entire thing was useless.

MyndFyre

Incidentally, that's not a restriction that C# imposes, but one that Win32 imposes.  User interface drawing is performed only in the primary thread, and updates that affect drawing must take place in that thread.  The Invoke() function allows that information to be marshaled back to the primary thread.

Yes, Joe is right in that it's because of a race condition.
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

Noodlez

One more question...
deals with multiple forms.
Application.OpenForms["Form2"].Controls["treeView1"].Nodes
.Nodes doesn't exist.
Any reccomendations?

K

Quote from: Noodlez on October 28, 2007, 01:43 PM
One more question...
deals with multiple forms.
Application.OpenForms["Form2"].Controls["treeView1"].Nodes
.Nodes doesn't exist.
Any reccomendations?

Yes, either address myForm2.treeView1 directly instead of going through Application.OpenForms, or something like the following:


Form2 someForm2 = (Form2)Application.OpenForms["Form2"];
someForm2.treeView1.Nodes ...
// or
(Application.OpenForms["Form2"].Controls["treeView1"] as TreeView).Nodes


The problem is that you are treating a generic base class as a derived class.  Application.OpenForms doesn't know about the Form2 class, so the return value is a Form.    Form.Controls doesn't know the type of each control it contains, just that they are Controls.  If you know that a certain Control is a TreeView (or that a certain Form is a Form2), you need to cast it to it.