Valhalla Legends Forums Archive | General Programming | C# Basic Question

AuthorMessageTime
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.
October 16, 2007, 7:25 AM
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.
October 16, 2007, 9:08 PM
DDA-TriCk-E
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...
[code]
        // 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);
            }
        }
[/code]

Then this goes in my "Connection" class:
[code]
        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;
[/code]

To initialize "AddChat" (within the connection class) you simply do something along the lines of this within the Form containing the RichTextBox:
[code]
        Connection c = new Connection();
        c.AddChat = new Connection.Output(AddChat);
[/code]

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...
October 17, 2007, 12:00 AM
Myndfyr
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.
October 17, 2007, 2:10 AM
DDA-TriCk-E
Thanks for the tip  ;)
October 17, 2007, 2:56 AM
JoeTheOdd
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.
October 17, 2007, 5:25 AM
Myndfyr
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.
October 17, 2007, 5:54 AM
Noodlez
One more question...
deals with multiple forms.
Application.OpenForms["Form2"].Controls["treeView1"].Nodes
.Nodes doesn't exist.
Any reccomendations?
October 28, 2007, 6:43 PM
K
[quote author=Noodlez link=topic=17112.msg174279#msg174279 date=1193597032]
One more question...
deals with multiple forms.
Application.OpenForms["Form2"].Controls["treeView1"].Nodes
.Nodes doesn't exist.
Any reccomendations?
[/quote]

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

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

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.
October 28, 2007, 7:23 PM

Search