TreeView node icon changes when selected only on custom icons in C# - c#

So I have a TreeView in C# and I'm loading icons for folders via P/Invoke. It's working, but on icons which are custom (so to speak), they change to some weird icon, as seen in the image below:
On "Regular" folders, i.e. ones without custom icons, this doesn't happen. Also on things like my HDD icons, it doesn't happen. This is the code I'm using to set the icon key
ImageKey = node.FileInfo.UniqueIcon;
SelectedImageKey = ImageKey;
As you can see, there's no way SelectedImageKey is different from ImageKey. However, the icon is still being set as the 0th index of the ImageList.I have confirmed via the debugger that the keys are staying the same, after the object is added.
So any ideas why this would be happening only for some icons?
Thanks.
Update
I found a workaround, but I'm not calling it a solution. If I add this to my code:
private void FolderTree_BeforeSelect(object sender, TreeViewCancelEventArgs e) {
e.Node.SelectedImageKey = e.Node.ImageKey;
}
I'm not calling it a solution, because that command only has to run once for it to work. I know that because if I put it on the AfterExpand event, then after it does it for one bad one, all the others work after that, even before they're expanded. So it's like something just isn't clicking until after, and resetting just one makes all others work.

Related

C#/WinForms tooltip stops displaying

I'm facing the following issue during setting up tooltips on a WinForms / C# desktop application (using .NET Framework version 4.5).
Application has hundreds of form elements where I would like to display a tooltip.
Current implementation as the following:
I have one toolTip object on my main form
Language file has been loaded and saved in an array
There is a method which suppose to assign the tooltip texts to the different elements accordingly by calling the SetToolTip method on the toolTip object.
E.g.
toolTip.SetToolTip(backBtn, LocalizationFile[0]);
toolTip.SetToolTip(myTextBox, LocalizationFile[1]);
It works fine, tooltips are displayed correctly.
As soon as I reach ca. 30 calls it stops working.
Calling ~30 times SetToolTip method to setup the required tooltips, cause to completely stop displaying the tooltips.
The previously worked tooltip texts are not getting display anymore.
There is no exception or any error message.
Can you please explain me why the toolTip object just stops displaying the texts after calling the SetToolTip method several times? Is there any workaround out there to apply in such cases?
EDIT-1
Following workaround works, but I'm still unsure what is the original problem.
I have created a method to call SetToolTip on the toolTip object, after calling the method, I re-create the toolTip instance using the "new" operator. That solves the issue. However as I want to disable anytime the tooltips on my application I also store all the references in a List. On that list I can iterate over to enable / disable all toolTip references according to what the user wants.
Basically there is a button to toggle the tooltips.
Do you have any idea, why this actually solves the original issue?
List<ToolTip> storeToolTipReferences = new List<ToolTip>(); //store tooltip references
//method begin called to set the tooltip on a control, store the reference of the tooltip and create a new instance
private void SetMyToolTip(Control ctrl, string toolTipText)
{
toolTip.SetToolTip(ctrl, toolTipText);
storeToolTipReferences.Add(toolTip);
toolTip = new ToolTip();
}
//called as the application loads or the user changes the language
private void SetAppLanguage(string[] LocalizationText)
{
storeToolTipReferences.ForEach(e => e.RemoveAll());
SetMyToolTip(ctrl1, LocalizationText[1]);
SetMyToolTip(ctrl2, LocalizationText[2]);
SetMyToolTip(ctrl3, LocalizationText[3]);
.....
}
//logic for tooltip enable/disable in my application
storeToolTipReferences.ForEach(t => t.Active = tooltip_control.Checked);
Thank you!

changing my windows form design removes some unrelated code

I'm having a strange issue that maybe being caused by my ignorance.
I have a treeview with an .AfterSelect and any time that i change the design of my form (in the deign view) the code gets removed for some reason.
here is my code
this.lstTreeView.AfterSelect += LstTreeView_AfterSelect; < this is the code that gets removed
this.lstTreeView.Location = new System.Drawing.Point(194, 56);
this.lstTreeView.Name = "lstTreeView";
this.lstTreeView.Size = new System.Drawing.Size(220, 498);
this.lstTreeView.TabIndex = 6;
this is the code that it allows to work.
private void LstTreeView_AfterSelect(object sender, System.Windows.Forms.TreeViewEventArgs e)
{
TreeNode CurrentNode = e.Node;
string fullpath = CurrentNode.FullPath;
MessageBox.Show(fullpath);
NrDirSearch(fullpath);
}
if anyone can give me some advice on why the .AfterSelect is being removed that would be really helpful.
I suggest you:
in the windows form designer, click the tree view to select it
in the properties grid click the lightning bolt and scroll to find the AfterSelect event
right click the name AfterSelect and choose reset
hit save all
Close out of the soution entirely/shut down visual studio
restart/reload the solution
Go back to the AfterSelect event as above, the box for which should be empty
click the drop down and choose your existing event handler
save all, quit and restart vs and check that the setting stayed
If you're finding it didn't stick, check that you don't have your designer open in another program e.g. A text editor that keeps autosaving an old version of the file that lacks the event handler?
Incidentally, the above process is how you add event in Design view - click the relevant control, lightning bolt, scroll to event wanted, double click the name of the event and you will be transported to your own code behind with a new named eventhandler created and ready to be filled
If you don't write any code in it, and go back to the designer and Reset the event as per the bulleted list instructions then your event handler method in your code will disappear. If you write code into the event handler then it is not removed when doing a reset, only empty handler methods are removed during reset
Side note: be careful with Undo if you see a message saying something like "performing this undo will cause a loss of work elsewhere" it usually indicates that the windows form design or designer.cs code will change as a result of actioning the undo
Designer files are safe to edit manually and it's sometimes necessary if the contents have gotten into a state where they are crashing the designer. I most often encounter this when deleting event handler s from my code that are still referenced in the designer. A screen appears saying a problem is preventing the forms designer from appearing, indicating the error line in the designer file. I have additionally in the past edited the designer directly to set large numbers of properties without the faff of using the designer - be mindful not to have a windows forms designer open at the same time as editing the designer.ca file because the forms designer will probably overwrite your changes. So long as you keep in mind that opening the same file in any two different editors at the same time can lead to conflict and loss of work, and take steps to ensure that edits in one editor are reflected in another before proceeding with further edits in the other editor, you'll be fine :)
Edit: having said that paragraph above, Mickey D made me realise an important point I'd overlooked:
The designer.cs file is read by the forms designer and uses to build the contents of the form, buttons, properties etc. As such if you are going to edit the designer.cs in a text editor you should limit your edits to only those things the forms designer can make use of, understand, represent and preserve when it next writes the file. Adding a line to set a button to enabled is fine. Removing a line that is causing it to crash is also good. Putting 27 methods that implement your entire program's database access strategy in is not a good idea as it will not be heeded or used to build the form when the designer reads the file and hence lost when the designer writes the file. If you're unsure of the difference between what will and won't be preserved stick to removing or fixing existing lines only rather than adding new lines of code
You should never[1] modify *.designer.cs files. They are code generated. Any changes you make are subject to being overwritten.
Instead either use the WinForms GUI Forms Designer to visually setup event handlers or you can do so in code in your form’s code-behind .cs file.
There are plenty of resources on the Net on how to use the WinForms designer.
[1] see Caius Jard's comment below for an exception to the rule that I concur with

can't get form to remain on top, in .net

I can't get a form to remain on top, in .net
I have checked How to make form always on top in Application and the answer there mentions form1.TopLevel = true; and I've checked How to make a window always stay on top in .Net? and it says Form.ActiveForm.TopMost so i've tried Form.ActiveForm.TopMost = true; and this.TopMost = true;
private void Form1_Load(object sender, EventArgs e)
{
this.TopLevel = true; //default anyway
Form.ActiveForm.TopMost = true;
this.TopMost = true;
}
But as you can see, a notepad window or any window can cover it.
Added
I have tried every suggestion made so far.
In response to Han's advice, "Of all the possible places to set TopMost property, the Load event is the worst. It should be set in the constructor, so the window gets created top-most right away. Or it should be set after it is visible, so after the Load event. Use the constructor. ". I tried putting those lines in the constructor.
public Form1()
{
InitializeComponent();
this.TopLevel = true; //default anyway
//Form.ActiveForm.TopMost = true; (commented to prevent a System.InvalidOperationException, presumably the form isn't yet active at this stage)
this.TopMost = true;
}
And the the other two suggestions, from others-
I tried setting the Form's TopMost field in the designer to True.
And running the EXE directly rather than just clicking play in visual studio.
Same issue.
And if you find that hard to believe, i've taken a 1min video here showing just that. https://screencast-o-matic.com/watch/cbXXrw2oTN
A potentially useful comment was mentioned..
Steve comments - "OK something definitively odd is happening here. I have tried to create a simple topmost form using linqpad and at the first run I get your same behavior. At the second run though everything works as expected."
A workaround, is this, following on from Han's point to put not put it in Load. Load is indeed too early. I've been finding that (at least on the system with the issue), The Constructor is also too early. I find that putting it in the Shown event, works.
One possible solution to this, is to run this patch, https://support.microsoft.com/en-us/help/2587473/topmost-windows-are-not-always-in-the-topmost-position-in-windows-7-or But be warned, if you want to uninstall it, I have some doubts whether it uninstalls correctly. And it's also not clear to me whether the patch is working or working sporadically. It likely works but it's hard for me to tell.
One commenter thought it's just my system, though that's not the case, as Steve ran into the same issue the first time he ran it. I find it may be most prone to happen after windows restarts, So, the program is running very fresh. But I find that putting that code in the Shown event, is fine and the form stays on top.
I tried instead of TopMost=true, using SetWindowPos, to set the window on top, I tried it fairly early like in the constructor, and late, like in the Shown event or on a button click, and I found it was fine in the Shown event or on a button click. So the issue was related to the TopMost=true line, or SetWindowPos line, firing too early, prior to the window it is setting appearing.
When calling SetWindowPos later one can use either this.Handle or GetForegroundWindow(), the former is easier as it's native. When calling it earlier one must use this.Handle. And using this.TopMost=true avoids all winAPI calls completely.
So in short, you could try the patch, though note that it might not uninstall right.. Or you can try the workaround of putting this.TopMost=true in the Shown event of the form.

c# & winforms - unable to set Image of ToolStripButton

This seems like a fairly basic thing to do, but for some reason it just fails silently:
/// <summary>
/// Sets the button to show it's busy image
/// </summary>
public void SetBusy()
{
if (Control is Button)
{ ((Button)Control).Image = BusyImage; }
else if (Control is ToolStripButton)
{ ((ToolStripButton)Control).Image = BusyImage; }
}
BusyImage is set using BusyImage = Properties.Resources.Busy;
If I debug this, I can see that the image appears to be setting correctly (if I hover over the Image member when at a breakpoint I can see it change), but it doesn't actually change the image when you look at the button.
I have noticed that this works when all the above code is hosted in the same Project file as the UI, but when it's shipped out to a different project (but within the same Solution), it fails silently.
Any ideas where I'm going wrong?
Thanks
EDIT 1:
Even trying to set the Image to a file from the Resources of the same project as the ToolStripButton doesn't work (still fails silently).
Interestingly, it works absolutely fine when using a normal Button, regardless of which project the images are in.
Why the difference in behaviour between Button and ToolStripButton?
EDIT 2:
It appears that moving the code that sets the image into the same project as the ToolStripButton works. However, I would like to keep it in a separate project if at all possible...
try this instead, tested it and working fine at my end:
public void ChangeImg(Component ctrl)
{
if (ctrl is Button)
{ ((Button)ctrl).Image = Properties.Resources.keylock; }
else if (ctrl is ToolStripButton)
{ ((ToolStripButton)ctrl).Image = Properties.Resources.keylock; }
}
Finally figured this out. To cut a long story short, I had some ToolStripButtons hidden somewhere in my form, only visible in the combobox in the designer's properties window (even when you select it from there, you can't see it on the form anywhere). I was passing the name of one of these to the ImageButton instead of the correct one (which had a default name like toolStripButton3)...
I'd love to know how it happened, I suspect user error on my part...but then again I find it strange that VS will allow a ToolStripButton to exist when it doesn't appear on any ToolStrip on the form.
Either way, my code seems to work quite happily now. The reason it appeared to work when run from the same project was that I was using a different button to test the theory.
Lots of process of elimination got it down to just two buttons that weren't playing ball; on a hunch I decided to compare the properties of the working and non-working buttons, whereupon I discovered the issue...

Unable to Affect Scintilla Control Programmatically at Runtime

I'm attempting to use the ScintillaNET control in an application I am working on. I drag and drop the control into my form and run form. The control appears on the form. This is good. In addition, if I set any of the properties in the control's properties editor (ConfigurationManager.Language, for example), I am able to type in that language and see syntax highlighting occur.
Where I run into problems is when I attempt to change properties programmatically. For example, I attempt to load text from a file into the form (I'm doing this in the form's Load). The text doesn't display. I also can't seem to show the line numbers or do any other number of tasks (including programmatically change the Language).
Any idea what I may be doing wrong? Even something as simple as the code below doesn't seem to work:
private void scintilla1_Load(object sender, EventArgs e)
{
scintilla1.ConfigurationManager.Language = "xml";
}
Simply add scintilla1.ConfigurationManager.Configure();
private void scintilla1_Load(object sender, EventArgs e)
{
scintilla1.ConfigurationManager.Language = "xml";
scintilla1.ConfigurationManager.Configure();
}
After spending some time playing around with the different events, it appears that I cannot affect the Scintilla control until after it is already visible. Hence, the "Load" event does not let me make any programmatic changes to the control until I've set it visible.
It's a little strange, and seems sort of pointless to me to have the Load event at all, but I just wanted to let everybody know what is happening in case someone else ran into the same problem.

Categories

Resources