PDA

Click to See Complete Forum and Search --> : create linklabel while not on activeform


Muller2
Oct 12th, 2006, 01:02 PM
Hi,

I have noticed a bug with my application, if the form doesn't have the focus (so its not the activeform) then my application throws an error.

Is there another way I can carry this out:

((Form1)Form1.ActiveForm).panel1.Controls.Add(aLabel);
I have tried all mannors of bits to try and remove the 'ActiveForm' element and it still compile correctly.

Is there a way to achieve this?

Many Thanks,

Al

jmcilhinney
Oct 12th, 2006, 05:15 PM
What error message are you getting? Please don't ever post that you're getting an error without giving us the error message.

Muller2
Oct 13th, 2006, 03:19 AM
the error msg is:

NullReferenceException was unhandled - Object reference not set to an instance of an object.

This line is highlighted:((Form1)Form1.ActiveForm).panel1.Controls.Add(aLabel);

I think its because the Form isn't selected and it doesn't have the focus within windows. Is there another way round this?

Thanks,

Al

jmcilhinney
Oct 13th, 2006, 09:32 AM
Why do you need to use ActiveForm at all, especially if it's not the active form? You know exactly which form you want to access so keep a reference to that form.

Muller2
Oct 13th, 2006, 09:37 AM
i've tried that. Everything I have tried to change it won't allow the application to compile.

I have tried the follow to replace the line I am having issue with and none allow the application to compile.

((Form1)Form1).panel1.Controls.Add(aLabel);

(Form1).panel1.Controls.Add(aLabel);

Form1.panel1.Controls.Add(aLabel);

panel1.Controls.Add(aLabel);


Can you help?

Thanks,

Al

jmcilhinney
Oct 13th, 2006, 09:43 AM
Read the "Forms in VB.NET" tutorial in my signature. The code is VB but the principles are exactly the same.

Muller2
Oct 15th, 2006, 01:10 PM
Read the "Forms in VB.NET" tutorial in my signature. The code is VB but the principles are exactly the same.

Fixed. Thanks

Muller2
Oct 16th, 2006, 02:23 PM
Hi,

I have found a issue with the fix - The solution was to change
private System.Windows.Forms.Panel panel1;
to
public static System.Windows.Forms.Panel panel1;

I then can reference the panel1 on Form1 by simply calling
Form1.panel1.Controls.Add(aLabel);and this allows the project to compile and execute correctly.

But whenever I make a change to the project like create a new button or label the protection level (I can't remember its name) is changed back to private and the project won't compile. The only solution is to manually go back and chage it to public static.

Is there away that I can make this change permenant?

Thanks,

Al

jmcilhinney
Oct 16th, 2006, 05:51 PM
That's a very bad solution. The 'static' keyword doesn't exist just as a convenient way to access members of other objects. Using the 'static' keyword makes a something a member of the class itself rather than a particular instance. That means that if you create 1000 instances of that form there will still only be one Panel. That is not right. If you do things properly then there's no need to use hacks like that. If you want to access formA from formB then should be passing formB a reference to formA. If you want to use a value in a method you pass that value to the method, correct? It's the same here. If you want to access one form in another then you pass the second form a reference to the first form.

Muller2
Oct 17th, 2006, 02:41 AM
jmcilhinney, does it matter that I don't actually have two forms? I have form1 and LinkLabelCollection.cs.

The object I am trying to access is panel1 located on the form1 and I am trying to call this from the LinkLabelCollection.cs class.

Thanks,

Al

jmcilhinney
Oct 17th, 2006, 02:47 AM
That I didn't realise, but the same situation applies. Frankly, it doesn't make sense to me that a LinkLabelCollection class would have any knowledge whatsoever of any forms or panels. A LinkLabelCollection, to my mind, is a place to put LinkLabels and keep them together. As far as I'm concerned, if the form needs a LinkLabel then it should be creating one, displaying it on this panel itself and then adding it to the collection. If the LinkLabelCollection doe have to be the one to place the label on a container then it should have a reference to that container, not be accessing it via some static member.

Muller2
Oct 17th, 2006, 12:31 PM
Hi,

Do you have any examples or could you show me how I can make the LinkLabels on the form1 and add the linklabel to the collection?

I have moved the Addnewlinklabel(); to my form1 as well as the event handlers and it almost compiles with the exception to the highlighted line.

public void AddNewLinkLabel()
{

LinkLabel aLabel = new LinkLabel();
LinkLabelCollection.List.Add(aLabel);
panel1.Controls.Add(aLabel);
//set linklabel properties
aLabel.AutoSize = true;
aLabel.LinkVisited = false;
aLabel.Visible = true;
aLabel.Top = 2;
aLabel.Height = 15;
aLabel.LinkColor = System.Drawing.Color.Black;
aLabel.LinkBehavior = System.Windows.Forms.LinkBehavior.HoverUnderline;
//this.linkLabel1.Font = new System.Drawing.Font("Verdana", (float)(10.0), FontStyle.Regular);
aLabel.Font = new System.Drawing.Font("Arial", (float)(9.0), System.Drawing.FontStyle.Bold);
aLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
// handler for clicked event of news title label
aLabel.LinkClicked += new LinkLabelLinkClickedEventHandler(ClickHandler);
aLabel.MouseMove += new MouseEventHandler(aLabel_MouseMove);
aLabel.MouseLeave += new EventHandler(aLabel_MouseLeave);
aLabel.MouseHover += new EventHandler(aLabel_MouseHover);
}


my linklabelcollection.cs looks like this now

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

namespace WindowsApplication5
{
public class LinkLabelCollection : CollectionBase
{
//private readonly UserControl hostControl;
private static bool bFirst = true;



public LinkLabelCollection()
{
//nothing
}



public LinkLabel this[int Index]
{
get
{
return (LinkLabel)this.List[Index];
}
}

public new void Clear()
{
//((Form1)Form1.ActiveForm).panel1.Controls.Clear();
Form1.panel1.Controls.Clear();
this.List.Clear();
}

public int maxlblWidth //getter for the length of the longest news title
{
get
{
int max = 0;
IEnumerator myEnum = this.GetEnumerator();

while (myEnum.MoveNext())
{
if (((LinkLabel)myEnum.Current).Width > max)
max = ((LinkLabel)myEnum.Current).Width;
}
return max;
}
}


}
}


Any help would be much appriciated.

Thanks,

Al

jmcilhinney
Oct 17th, 2006, 06:18 PM
The idea of creating a strongly-typed collection that inherits CollectionBase is that YOU reproduce the functionality of the ArrayList but instead of arguments and return values of type Object you're supposed to use your own type. You don't access the List property of the collection from outside. The idea is that YOU are supposed to declare your own Add method that can only accept LinkLabel objects. This code should be within your LinkLabelCollection class:public int Add(LinkLabel value)
{
return this.List.Add(value);
}The List property exposes an ArrayList whose Add method can accept any type of object, so you warp it in your own method that can only accept a LinkLabel object. Internally you add the object to the ArrayList and get the result, but from the outside you're adding a LinkLabel object to a LinkLabelCollection. You need to reproduce all the other members of the ArrayList class that accept or return Object references too. You've already done the indexer. Now you know how to do the Add method. You apply the same principle to Remove, Insert, etc.

Muller2
Oct 18th, 2006, 02:44 PM
jmcilhinney,

I added the code you provided to the LinkLabelCollection.cs and changed the following:


LinkLabelCollection.List.Add(aLabel);

TO

lblCollection.Add(aLabel);


And it compiles successfully :D

I have 4 further questions:

1) In the LinkLabelCollection.cs, I have Add and Index as you mentioned but do I need a clear? Simular to this?

public new void Clear()
{
this.List.Clear();
}

To clear the list before I recreate the list upon reload of the XML list?

2) How can I make my application less resource heavy? I would like to stream line it if possible. Are there things that I should be looking out for?

3) I am loading XML feeds for this application, but should I be caching them locally and checking for updates without downloading the full feed? The feeds aren't mine and most don't have Timestamps to check which is a shame!

4) Between the LinkLabels that are added to my panel1, I would like to have a hypen (-) or something to clearly define different LinkLabels. Any idea's how I can do this?

Sorry for a load of questions, just trying to learn from you and your thoughts and opinions are very helpful ;)

Many Thanks,

Al

jmcilhinney
Oct 18th, 2006, 05:24 PM
1. Your strongly-typed collection should basically reproduce the functionality of the ArrayList but refuse to store anything but your chosen type. CollectionBase provides some members for you, specifically the ones that are not type-dependent. The Clear method is one of those. You don't need to know the type of the items to clear the collection. There are no arguments or return value to be typed so there's no point creating a different implementation for each collection. RemoveAt is another example of a member provided by CollectionBase because it is not type-dependent. Look at the member listing for CollectionBase and compare it to that of ArrayList. Basically you need to provide your collection with all the members of ArrayList that CollectionBase lacks.

2. That's too general a question to answer briefly. There is plenty of information on optimisation on MSDN or the Web in general.

3. I don't know. Never really done that myself.

4. You may not be aware but you can have multiple links in a single LinkLabel. You could put the text for as many links as you like in the one LinkLabel with dashes between them. You control which parts of the Text are links using the Links property, which is a collection of Link objects which are defined by their Start index and Length. Otherwise you would have to either use normal Labels between each pair of LinkLabels or else use GDI+ to draw your dashes.