|
Since I have no idea why you are trying to do this, I can't really suggest anything concrete at this point.
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
|
If you want to automate a web browser from a desktop application, then you'll need to use a tool designed to do that - for example, Selenium[^].
Alternatively, you could use a tool such as Power Automate[^] to automate your interaction with the site. That has extensions for the three main browsers, as well as the now-deceased Internet Explorer: Automate webpages - Power Automate | Microsoft Learn[^]
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
I work with many Com-ports and to make them easier to keep track of I've created a combobox that has a fixed prefix (the information from the Device Manager, e.g. "STMicroelectronics STLink Virtual COM Port (COM21)") and an editable suffix where I can type in e.g. "My Product A". The code works great, but now I would like to also be able to disable (make the text gray) items in my combobox and it works fine in the dropdown list, but as soon as I close the dropdown list and only the selected item is shown, then the text is always enabled (black, not gray). Does anybody know what I should correct in my code to get the desired behavior?
partial class SemiEditableComboBox
{
private System.ComponentModel.IContainer components = null;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
private void InitializeComponent()
{
this.comboBox = new System.Windows.Forms.ComboBox();
this.SuspendLayout();
this.comboBox.FormattingEnabled = true;
this.comboBox.Location = new System.Drawing.Point(0, 0);
this.comboBox.Name = "comboBox";
this.comboBox.Size = new System.Drawing.Size(454, 24);
this.comboBox.TabIndex = 0;
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.comboBox);
this.Name = "SemiEditableComboBox";
this.Size = new System.Drawing.Size(454, 24);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.ComboBox comboBox;
}
public delegate void DelegateItemAndString(object item, string newString);
class SemiEditableComboBoxItem
{
public string lastString;
public string fixedPrefix;
public DelegateItemAndString editableSuffixChanged;
public bool enabled;
public SemiEditableComboBoxItem(string lastString, string fixedPrefix, DelegateItemAndString editableSuffixChanged, bool enabled)
{
this.lastString = lastString;
this.fixedPrefix = fixedPrefix;
this.editableSuffixChanged = editableSuffixChanged;
this.enabled = enabled;
}
}
public partial class SemiEditableComboBox : UserControl
{
private volatile bool modifySelection = false;
private int currentlySelectedIndex;
private List<SemiEditableComboBoxItem> items;
public event EventHandler SelectedIndexChanged;
public SemiEditableComboBox()
{
Font = new Font(Font.Name, 8.25f * 96f / CreateGraphics().DpiX, Font.Style, Font.Unit, Font.GdiCharSet, Font.GdiVerticalFont);
InitializeComponent();
this.comboBox.Width = this.Width;
this.comboBox.Height = this.Height;
items = new List<SemiEditableComboBoxItem>();
this.Resize += new EventHandler(delegate(object sender, EventArgs e)
{
this.comboBox.Width = this.Width;
this.comboBox.Height = this.Height;
});
this.comboBox.SelectedIndexChanged += new EventHandler(comboBox_SelectedIndexChanged);
this.comboBox.TextChanged += new EventHandler(comboBox_TextChanged);
this.comboBox.DrawMode = DrawMode.OwnerDrawFixed;
this.comboBox.DrawItem += comboBox_DrawItem;
}
protected override void OnPaint(PaintEventArgs e)
{
if (modifySelection)
{
modifySelection = false;
if ((comboBox != null) && (currentlySelectedIndex < items.Count) &&
(items[currentlySelectedIndex] != null) &&
(!string.IsNullOrEmpty(items[currentlySelectedIndex].fixedPrefix)))
{
comboBox.SelectionStart = items[currentlySelectedIndex].fixedPrefix.Length;
comboBox.SelectionLength = 200;
}
}
}
private void comboBox_DrawItem(object sender, DrawItemEventArgs ea)
{
ea.DrawBackground();
ea.DrawFocusRectangle();
Rectangle bounds = ea.Bounds;
bool enableItem = (ea.Index < 0) ? false : ((SemiEditableComboBoxItem)items[ea.Index]).enabled;
Font myFont = new Font(ea.Font, FontStyle.Italic);
if (ea.Index != -1)
{
ea.Graphics.DrawString(comboBox.Items[ea.Index].ToString(), ea.Font, new SolidBrush(enableItem ? Color.Black : Color.Gray), bounds.Left, bounds.Top);
}
else
{
ea.Graphics.DrawString(Text, ea.Font, new SolidBrush(Color.Gray), bounds.Left, bounds.Top);
}
}
private void comboBox_SelectedIndexChanged(object sender, EventArgs e)
{
currentlySelectedIndex = this.comboBox.SelectedIndex;
if (SelectedIndexChanged != null)
{
SelectedIndexChanged(sender, e);
}
modifySelection = true;
this.Invalidate();
}
private void comboBox_TextChanged(object sender, EventArgs e)
{
int selectedIndex = comboBox.SelectedIndex;
if (0 <= selectedIndex)
{
currentlySelectedIndex = selectedIndex;
}
if (items[currentlySelectedIndex].editableSuffixChanged == null)
{
this.comboBox.TextChanged -= new EventHandler(comboBox_TextChanged);
comboBox.Text = items[currentlySelectedIndex].lastString;
this.comboBox.TextChanged += new EventHandler(comboBox_TextChanged);
return;
}
else if (this.comboBox.Text.StartsWith(items[currentlySelectedIndex].fixedPrefix))
{
items[currentlySelectedIndex].lastString = comboBox.Text;
}
else
{
this.comboBox.TextChanged -= new EventHandler(comboBox_TextChanged);
comboBox.Text = items[currentlySelectedIndex].lastString;
this.comboBox.TextChanged += new EventHandler(comboBox_TextChanged);
}
if (!this.comboBox.Items[currentlySelectedIndex].ToString().Equals(items[currentlySelectedIndex].lastString))
{
this.comboBox.TextChanged -= new EventHandler(comboBox_TextChanged);
this.comboBox.DrawMode = DrawMode.OwnerDrawFixed;
if (items[currentlySelectedIndex].editableSuffixChanged != null)
{
items[currentlySelectedIndex].editableSuffixChanged(comboBox.Items[currentlySelectedIndex], items[currentlySelectedIndex].lastString.Substring(items[currentlySelectedIndex].fixedPrefix.Length));
}
this.comboBox.DrawMode = DrawMode.Normal;
this.comboBox.DrawMode = DrawMode.OwnerDrawFixed;
this.comboBox.TextChanged += new EventHandler(comboBox_TextChanged);
}
comboBox.SelectionStart = items[currentlySelectedIndex].lastString.Length;
comboBox.SelectionLength = 0;
}
public void addItem(object item, string initialText, string fixedPrefix, DelegateItemAndString editableSuffixChanged)
{
addItem(item, initialText, fixedPrefix, editableSuffixChanged, false);
}
public void addItem(object item, string initialText, string fixedPrefix, DelegateItemAndString editableSuffixChanged, bool enabled)
{
comboBox.Items.Add(item);
items.Add(new SemiEditableComboBoxItem(initialText, fixedPrefix, editableSuffixChanged, enabled));
}
public int itemsCount
{
get
{
return comboBox.Items.Count;
}
}
public void setItemEnabled(int index, bool enabledOrDisabled)
{
items[index].enabled = enabledOrDisabled;
}
public bool getItemEnabled(int index)
{
return items[index].enabled;
}
public void clearAllItems()
{
comboBox.Items.Clear();
items.Clear();
}
public int selectedIndex
{
get
{
return currentlySelectedIndex;
}
set
{
this.comboBox.SelectedIndexChanged -= new EventHandler(comboBox_SelectedIndexChanged);
comboBox.SelectedIndex = value;
modifySelection = true;
this.Invalidate();
this.comboBox.SelectedIndexChanged += new EventHandler(comboBox_SelectedIndexChanged);
}
}
public object selectedItem
{
get
{
return comboBox.Items[selectedIndex];
}
}
public object getItem(int index)
{
return comboBox.Items[index];
}
public DrawMode drawMode
{
set
{
this.comboBox.DrawMode = value;
}
}
}
|
|
|
|
|
You manually draw the items yourself in the comboBox_DrawItem event handler - and that means you select the Brush in which they are drawn. In order to "grey out" selections, you'd need to change the enable code you have there.
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
I'm not sure I understand what you mean. Even if I do a global replace Color.Black -> Color.Gray then the selected item still has black color, not gray, when the dropdown list isn't shown.
|
|
|
|
|
are you sure that enableItem is really false when DrawItem is called ?
|
|
|
|
|
I added Debug.WriteLine(enableItem ? "Enabled" : "Disabled"); inside comboBox_DrawItem and it always prints "Disabled".
|
|
|
|
|
another try :
I would assign the color depending on the enableItem outside the DrawString-call.
Use this variable for DrawString and also for Debug.WriteLine.
In the Moment I can't see a mistake ...
|
|
|
|
|
So, the DrawItem event is used to draw the items that appear in the dropdown list and not the actual selected value. The colour of the selected text is set by ForeColor . It seems to me that the simple solution would be to change the ForeColor , depending on whether the selection was enabled or not. Something like this:
private void comboBox_TextChanged(object sender, EventArgs e)
{
bool enableItem = (SelectedIndex < 0) ? false : comboBox.Items[SelectedIndex]).enabled;
comboBox.ForeColor = enableItem ? Color.Black : Color.Gray;
}
|
|
|
|
|
Yes, that was it!!! Thank you. The beginning of my comboBox_TextChanged method now looks like this:
private void comboBox_TextChanged(object sender, EventArgs e)
{
int selectedIndex = comboBox.SelectedIndex;
if (0 <= selectedIndex)
{
currentlySelectedIndex = selectedIndex;
}
bool enableItem = (selectedIndex < 0) ? false : items[selectedIndex].enabled;
comboBox.ForeColor = enableItem ? Color.Black : Color.Gray;
|
|
|
|
|
I'm glad it's working now. Sorry I only just got the chance to look at this.
|
|
|
|
|
The terse descriptions here apply to WinForms "classic," not WinForms "Core," which I have found unusable, so far.
It's easy to write a Windows Class Library that compiles into a .Dll. I can put a static Class in that code, and declare methods with void or return types, or even Extension methods.
Using that .DLL in a new WinForms app project is easy:
// assuming thew Dll is named ",,, / TestDLL1
// in the WinForms project which has a reference to TestDLL1
// where the static class in TestDLL1 is named: TestDLLExtension
using static TestDLL1.TestDLLExtension;
Now: what I can't achieve.
1) I write another Class library, named 'ExtensionsLibrary,' that has a reference to TestDLL1
2) I now add a reference to the ExtensionsLibrary DLL tto the WinForms project.
3) the WinForms project has the refrencee to TestDLL1 removed.
I can't find any way to use 'using that allows me to access/use the static methods in TestDll1 referemced by ExtensionsLibrary.
In other words, I cannot achieve an "outer" DLL that has referrences to other, "inner," DLL's.
Perhaps my error is in thinking this is possible ?
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
|
|
|
|
|
For NuGet references, pulling in package A will also pull in all transitive dependencies of package A:
NuGet Package Dependency Resolution | Microsoft Learn[^]
For assembly references, that doesn't happen. If your project references assembly A, but not assembly B, you won't be able to use any of the methods defined in assembly B. And if you call any methods in assembly A that (directly or indirectly) rely on assembly B, you will get a run-time exception unless assembly B can be located. (eg: The assembly is deployed to the output directory, or the assembly is installed in the GAC.)
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Thanks, Richard. What I am describing does not use NuGet: it has never occurred to me to try and load a DLL via NuGet ... if that is what you are suggesting.
In this case, assembly A (DLL) has a reference to assembly B (DLL), and a "using static" using statement to the static class in B.
The WinForm app has a reference to A, and I am seeking to call static methods in B from A.
If that is not possible, okay.
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
|
|
|
|
|
BillWoodruff wrote: If that is not possible, okay.
Correct. As I said, assembly references don't automatically pull in transitive dependencies, so your WinForms app doesn't actually have a reference to B.
I've largely switched to using a private Azure DevOps NuGet feed[^] for cross-solution dependencies. It means other developers can work on my projects without needing to have the correct versions of the referenced assemblies in the same physical or relative path, as well as ensuring that transitive dependencies are always pulled in.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Thanks, agaib !
As I said to Griff: "You can always make one DLL with multiple static classes, and reference/expose whichever ones you desire ... so my question is kind of academic."
Re your use of NuGet and Azure: fascinating; I'm kind of ... by choice ... still using older non-web simple stuff, like WinForms ... other non-technical priorities in my life, now, like staying alive
Re your signature with quote from Homer: if you happen to be interested in the "mind of Homer," I can send you a link to the most remarkable essay (introduction to a newer translation) on the Attic context out of which Iliad, and Odyssey arise.
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
|
|
|
|
|
BillWoodruff wrote: Re your signature with quote from Homer
Wrong Homer.
Quote: Marge: Homer, a man who called himself "you-know-who" just invited you to a secret "wink-wink" at the "you-know-what". You certainly are popular now that you're a Stonecutter.
Homer: Oh, yeah. Beer busts, beer blasts, keggers, stein hoists, AA meetings, beer night. It's wonderful, Marge. I've never felt so accepted in all my life. These people looked deep within my soul and assigned me a number based on the order in which I joined.
Homer the Great[^]
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Oh, that Homer
I nominate this exchange with you for "CP Surreal Posts of the Year."
p.s. once you study moods in Homeric Greek, indicative, imperative, interrogative, conditional, and subjunctive ... neurons are ... permanently altered. it took me years to forget them.
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
modified 9-Jan-23 9:12am.
|
|
|
|
|
The using statement establishes a "shortcut" alternative to using the full name of a class: "Form" instead of writing "System.Windows.Forms.Form" each time you want to use it.
It doesn't add a namespace to the project - to access those you need to have a refence to the containing assembly.
Your ExtensionsLibrary assembly is already built with the reference it needs (and every assembly that uses ExtensionLibrary will need access to the TestDLL1 assembly file in order to work) but that doesn't include the subassemblies when you add a reference to it, so using doesn't "know" where to point the shortcut - any more than you can use the full name of a class and the system can work out which .DLL or .EXE file contains it.
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
modified 9-Jan-23 4:56am.
|
|
|
|
|
Thanks, Griff,
imho, "using static" is kind of a different beast: it sure works fine to expose the public static class in a referenced DLL, and its methods ... the "simple" use case I describe first.
If a "nested" DLL ... the second example ... is not referenceable, not a problem.
You can always make one DLL with multiple static classes, and reference/expose whichever ones you desire ,,, so my question is kind of academic.
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
|
|
|
|
|
To illustrate why my question is academic, and, how simple it can be to have multiple static classes in one DLL, and expose your choice of them and their methods, I offer a terse example:
1) create a WinForm class library with multiple static classes and public static methods: TestDLL_1_1_2023
2) compile it
3) in a WinForm app: reference the compiled DLL.
4) use "static using" statements to expose your choice of methods:
// expose string methods
using static TestDLL_1_1_2023.StupidStringExtensions;
// do not expose numeric methods
// using static TestDLL_1_1_2023.StupidNumericExtensions;
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
|
|
|
|
|
i create dynamic textbox and button save app windows form, but i can't insert data to dynamic textbox after i create event button click save
private void Createtextbox()
{
TextBox textboxUsername = new TextBox();
textboxUsername.Location = new Point(420, 50);
textboxUsername.Size = new Size(500, 30);
textboxUsername.Name = "text_user";
System.Web.UI.WebControls.RequiredFieldValidator rq = new System.Web.UI.WebControls.RequiredFieldValidator();
rq.ErrorMessage = "Error is for Dynamic Control";
rq.BorderColor = Color.Red;
rq.ControlToValidate = "DynControl";
this.Controls.Add(textboxUsername);
TextBox textboxPassword = new TextBox();
textboxPassword.Location = new Point(420, 80);
textboxPassword.Size = new Size(500, 30);
textboxPassword.Name = "text_pass";
this.Controls.Add(textboxPassword);
TextBox textboxMail = new TextBox();
textboxMail.Location = new Point(420, 110);
textboxMail.Size = new Size(500, 30);
textboxMail.Name = "text_mail";
this.Controls.Add(textboxMail);
Button btnSave = new Button();
btnSave.Location = new Point(420, 150);
btnSave.Name = "Submit";
btnSave.Size = new Size(80, 26);
btnSave.Click += new EventHandler(btnSave_Click);
this.Controls.Add(btnSave);
}
private void btnSave_Click(object sender, EventArgs e)
{
try
{
if (this.ValidateChildren())
{
//Here the form is in valid state
//Do what you need when the form is valid
TextBox textboxUsername = (TextBox)sender;// textboxUsername not instal
}
else
{
var listOfErrors = this.errorProvider1.ContainerControl.Controls.Cast<Control>()
.Select(c => this.errorProvider1.GetError(c))
.Where(s => !string.IsNullOrEmpty(s))
.ToList();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
|
|
|
|
|
The sender parameter is the control that raised the event - which for a button Click event would be a Button not a TextBox. Since the Button and TextBox controls do not inherit from each other, you cannot cast from one to the other, any more than you can use an Apple like an Orange although they are both Fruits.
Your TextBox called textboxUsername is local to the Createtextbox method, and can't be accessed outside it except by going via the Controls collection and finding the specific control.
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
|