Using WinForm "button.visible" as parameter to method - c#

I'm creating Library app using WinForms.
I have eLibraryClasses where I have all data including each form services, and eLibraryUI where I have all my WinForms.
I have a problem in one form where I would like to change states of button.Visible to false or true.
I tried to extract method from UI to Service like:
public void ShowDrawnBook(bool clickedButtonVisible, bool toReadButtonVisible, int buttonNumber)
{
//Hide button which cover answer
clickedButtonVisible = false;
//Add option to add randomized book to "To read" bookshelf
toReadButtonVisible = true;
//Return index of clicked button
buttonClicked = buttonNumber;
}
And UI looks like for example:
service.ShowDrawnBook(randomBook2Button.Visible, toReadButton.Visible, 2);
I tried, but I couldn't use "ref" neither "out" for this properties.
And in this way above it's building properly, but not working because of not changing parameters out of method.
I have such a many of them in this form, so I could do it like
randomBook2Button.Visible = SomeMethod();
toReadButton.Visible = SomeMethod();
... for every variable
But I would like to avoid it.
Is there any way to send there buttons properties (bools) as parameters?

Booleans are passed by value, not reference, thus your "problem".
To solve your problem, just take the Button(s) as parameters instead of the booleans. Button is a class, thus is passed by reference.
Then in your method change the state of the Button(s) properties as you see fit.
public void MyMethod(Button myButton1, Button myButton2)
{
myButton1.Visible = true;
myButton2.Visible = false;
}

Related

If statement condition where element equals element

I am testing a web page that contains a table. You can click a "Create new" link to add records to the grid. Once "Create New" is clicked, a dialog appears with some text boxes, another grid and a Cancel and Save button. You can then click a link to add a record to the dialog's grid which makes another dialog appear with text boxes and a Cancel and Save button. At my test level class, I currently click on these buttons then wait for the dialog's to open or close. I need to formulate a generic method which encompasses both the click and the wait, for each and every button. So instead of 2 lines of code at my test level to click an element and wait for a window, I would have one line of code that handles that. Below is my dilemma:
I need to be able to apply an If condition where a passed parameter of IWebElement equals a certain IWebElement, but it does not allow me to do this. The if statement doesn't find a match for some reason, so code inside the if statement never gets reached. Am I missing something? If not, is there a workaround?
NOTE: Using button.text == SaveOrganizationBtn.Text is a workaround, but would fail in my specific case, because some of these buttons might not have been loaded into the HTML for a certain test (i.e. A form has not been invoked), so the if statement fails. It would never be able to grab the Text property because it cant find the element in the first place.
Example code:
ClickButton(SaveNetworkBtn);
public void ClickButton(IWebElement button)
{
if (button == SaveOrganizationBtn)
{
SaveOrganizationBtn.Click();
WaitForOrganizationFormToClose();
}
if (button == SaveNetworkBtn)
{
SaveNetworkBtn.Click();
WaitForNetworkFormToClose();
}
Use the Equals() method for your scenario. == will not work for this. you need to check it as if(button.Equals(SaveOrganizationBtn)). The result for this will be true, if it is the same object else it will return false.
I hope, it will help you.
I found a solution, however awkward it might look. I will mark this as the answer if no one else provides a better solution.
ClickButton(SaveNetworkBtn);
public bool ClickButton(IWebElement button)
{
bool buttonClicked = false;
if (Driver.FindElements(By.Id("SaveOrg-Button-ID")).Count > 1)
{
if (button == SaveOrganizationBtn)
{
SaveOrganizationBtn.Click();
WaitForOrganizationFormToClose();
buttonClicked = true;
return buttonClicked;
}
}
if (Driver.FindElements(By.Id("SaveNet-Button-ID")).Count > 1)
{
if (button == SaveNetworkBtn)
{
SaveNetworkBtn.Click();
WaitForNetworkFormToClose();
buttonClicked = true;
return buttonClicked;
}
}
return buttonClicked;
}
I don't fully understand your scenario but it seems like something like this might work... you will have to decide. Instead of passing in button, just check if the button exists on the page, if it does... click it.
ClickButton();
public bool ClickButton()
{
IReadOnlyCollection<IWebElement> saveOrg = Driver.FindElements(By.Id("SaveOrg-Button-ID"));
if (saveOrg.Any())
{
saveOrg.ElementAt(0).Click();
WaitForOrganizationFormToClose();
return true;
}
IReadOnlyCollection<IWebElement> saveNet = Driver.FindElements(By.Id("SaveNet-Button-ID"));
if (saveNet.Any())
{
saveNet.ElementAt(0).Click();
WaitForNetworkFormToClose();
return true;
}
return false;
}
NOTE: .Any() works the same as .Count > 0, I found it a while back and like it a little better but it's a personal preference.

Best place to implement DataGridView extension method for changes

I hope this isn't a trivial question as I'm still pretty new to VS C# and WINFORMS.
T.Rahgooy answered a question on link How do I make a DataGridView immediately commit edits? It didn't get any votes but looked like something I'd like to try and so far it appears to work beautifully.
Being pretty new to VS C# & Winforms I was unsure where to install it and where to call it. I placed it at the top of my namespace (had to create a class to contain it first) and then called it from RowDirtyStateNeeded event (which I added)
Questions:
1) Is there a better place to install the extension method, i.e. an existing class ?
2) Is there a better place to call the method?
namespace VX130
{
public static class ExtensionHelpers
{
public static void ChangeEditModeToOnPropertyChanged(this DataGridView gv)
{
//Use this extension method. It works for all columns types, not just ComboBoxes:
// This method commits every change just after the change is made. When we have a text column, after typing a character,
//its value will commit to the DataSource and the editmode of the cell will end. Therefore current cell should return to
//ed
gv.CurrentCellDirtyStateChanged += (sender, args) =>
{
gv.CommitEdit(DataGridViewDataErrorContexts.Commit);
if (gv.CurrentCell == null)
return;
if (gv.CurrentCell.EditType != typeof(DataGridViewTextBoxEditingControl))
return;
gv.BeginEdit(false);
var textBox = (TextBox)gv.EditingControl;
textBox.SelectionStart = textBox.Text.Length;
}
}
}
}

C# Dynamic form (reflection) - linking controls

Sorry for the poor quality of the title. I couldn't think of a better way to phrase this.
For a project I'm currently working on with a few friends, I got myself in the situation where I have created a dynamic form (with reflection) which I now want to validate.
Example (ignore the black box, it contains old form elements which are now irrelevant and i didn't want to confuse you guys):
As you may have guessed already, it is an application for creating a mysql database.
Which is where I get to my problem(s). I want to disable checkboxes if others are checked.
For example: If I check "PrimaryKey" I want to disable the checkbox "Null".
Changing from unsigned to signed changes the numericupdown minimum and maximum etc.
But with reflection and all, I find it difficult to know exactly which checkbox to disable.
I was hoping you guys would have some suggestions.
I have been thinking about this for a while and a few thoughts have come to mind. Maybe these are better solutions than the current one.
Thought 1: I create UserControls for every datatype. Pro's: no problems with reflection and easy identifying of every control in the UserControl for validation. Con's: Copy-Pasting, Lots of UserControls, with a lot of the same controls.
Thought 2: Doing something with the description tags for every property of the classes. Creating rules in the description that allow me to link the checkboxes together. Here I'll only have to copy the rules to every class property and then it should be ok.
I had been thinking of other solutions but I failed to remember them.
I hope you guys can give me a few good pointers/suggestions.
[Edit]
Maybe my code can explain a bit more.
My code:
PropertyInfo[] properties = DataTypes.DataTypes.GetTypeFromString(modelElement.DataType.ToString()).GetType().GetProperties();
foreach (PropertyInfo prop in properties)
{
if (prop.Name != "Label" && prop.Name != "Project" && prop.Name != "Panel")
{
var value = prop.GetValue(modelElement.DataType, null);
if (value != null)
{
tableLayoutPanel1.Controls.Add(new Label { Text = prop.Name, Anchor = AnchorStyles.Left, AutoSize = true });
switch (value.GetType().ToString())
{
case "System.Int32":
NumericUpDown numericUpDown = new NumericUpDown();
numericUpDown.Text = value.ToString();
numericUpDown.Dock = DockStyle.None;
tableLayoutPanel1.Controls.Add(numericUpDown);
break;
case "System.Boolean":
CheckBox checkBox = new CheckBox();
checkBox.Dock = DockStyle.None;
// checkbox will become huge if not for these changes
checkBox.AutoSize = false;
checkBox.Size = new Size(16, 16);
if (value.Equals(true))
{
checkBox.CheckState = CheckState.Checked;
}
tableLayoutPanel1.Controls.Add(checkBox);
break;
default:
MessageBox.Show(#"The following type has not been implemented yet: " + value.GetType());
break;
}
}
}
}
Here is a mockup from my comments:
// The ViewModel is responsible for handling the actual visual layout of the form.
public class ViewModel {
// Fire this when your ViewModel changes
public event EventHandler WindowUpdated;
public Boolean IsIsNullCheckBoxVisible { get; private set; }
// This method would contain the actual logic for handling window changes.
public void CalculateFormLayout() {
Boolean someLogic = true;
// If the logic is true, set the isNullCheckbox to true
if (someLogic) {
IsIsNullCheckBoxVisible = true;
}
// Inform the UI to update
UpdateVisual();
}
// This fires the 'WindowUpdated' event.
public void UpdateVisual() {
if (WindowUpdated != null) {
WindowUpdated(this, new EventArgs());
}
}
}
public class TheUI : Form {
// Attach to the viewModel;
ViewModel myViewModel = new ViewModel();
CheckBox isNullCheckBox = new CheckBox();
public TheUI() {
this.myViewModel.WindowUpdated += myViewModel_WindowUpdated;
}
void myViewModel_WindowUpdated(object sender, EventArgs e) {
// Update the view here.
// Notie that all we do in the UI is to update the visual based on the
// results from the ViewModel;
this.isNullCheckBox.Visible = myViewModel.IsIsNullCheckBoxVisible;
}
}
The basic idea here is that you ensure that the UI does as little as possible. It's role should just be to update. Update what? That's for the ViewModel class to decide. We perform all of the updating logic in the ViewModel class, and then when the updating computations are done, we call the UpdateVisual() event, which tells the UI that it needs to represent itself. When the WindowUpdated Event occurs, the UI just responds by displaying the configuration set up by the ViewModel.
This may seem like a lot of work to set up initially, but once in place it will save you tons and tons of time down the road. Let me know if you have any questions.
Try relating the event of one checkbox to disable the other; something like this:
private void primaryKeyBox_AfterCheck(object sender, EventArgs e)
{
nullBox.Enabled = false;
}
This is a very simple example and would have to be changed a bit, but for what I think you're asking it should work. You would also have to add to an event for the boxes being unchecked. You would also need logic to only get data from certain checkboxes based on the ones that are and are not checked.
For all the other things, such as changing the numbers based on the dropdown, change them based on events as well.
For WinForms I would use data binding.
Create an object and implement INotifyPropertyChanged and work with that object.
Then, If you have an object instance aObj:
To bind the last name property to a textbox on the form do this:
Private WithEvents txtLastNameBinding As Binding
txtLastNameBinding = New Binding("Text", aObj, "LastName", True, DataSourceUpdateMode.OnValidation, "")
txtLastName.DataBindings.Add(txtLastNameBinding)
Take a look here for more info.
INotifyPropertyChanged

Click a custom control and show some variables related to it in another control

in my Win Forms app I create an array of dynamic custom controls inside a loop. These, lets call them 'boxes', are like my basic pieces of information. I also create string arrays in other parts of the code that contain the information of this 'boxes', so that for example string[3] is a variable of box[3] and so does stringa[3], stringb[3], stringc[3]... all the arrays with the same index are related to the box with that index. Hope I make myself clear.
Only 2 of this strings are shown in 2 labels inside each custom control 'box' in the array, but the others are there because I want to make something so that when the user clicks one of these controls the other strings can be shown in another control. Sort of something like "More Information...". All the 'boxes' in the array need to have the same event handler because I create +100.
To put it more into context, each custom control 'box' in the array shows the Symbol and the Price of a stock and I want that when the user clicks on each stock more quote information is shown on another special control which is like a placeholder for "More info".
I am thinking of 2 ways to do it:
If I could "detect" the index of the clicked control (which is the same in the strings related to it), I could just set this to an int j and all I have to do is show all the strings a,b,c... with index j. Unfortunately I cannot find a way to do this, maybe it is not even possible.
The other way I have thought is to create some properties for my custom control which "store" this variables, and in my app instead of assigning strings I would set properties for each control, which I could later retrieve when the control is clicked. I haven't tryed this because I don't know exactly how to do it.
What do you think? Do you know how can I achieve this or do you have a different idea that will work? Please help! Thanks in advance.
It's kind of a broad implementation question since there are countless ways you could implement something like this.
If you are creating two collections, one with the buttons and one with the information, you potentially could just assign each of the buttons 'Tag' properties to point to the corresponding info and assign a generic OnClick event handler that displays the info.. something like:
infoControl.text = ((InfoClass)((Button)Sender.Tag)).pieceOfInformation;
But again there are many ways to do this, and the choice comes down to how you store your information.
For your first method, you could have a property of your custom control that is the index.
public class Box : Control
{
// ...existing code
private int index;
public int Index
{
get
{
return index;
}
set
{
index = value;
}
}
}
OR
For your second method, you could have a property of your custom control that is the additional info string.
public class Box : Control
{
// ...existing code
private string extraInfo;
public string ExtraInfo
{
get
{
return extraInfo;
}
set
{
extraInfo = value;
}
}
}
In either case, you could then access the proper information right in your click handler for the "box".
i don't know about the first way - got to noodle around more, but in the second way you can extended your custom or built-in control: for example:
public class ExtendedLabel: Label
{
public string[] MoreInfo { get; set; }
}
and initialize it
public TestForm()
{
InitializeComponent();
ExtendedLabel label = new ExtendedLabel();
label.MoreInfo = new string[] { "test" };
this.Controls.Add(label);
label.AutoSize = true;
label.Location = new System.Drawing.Point(120, 87);
label.Name = "label1";
label.Size = new System.Drawing.Size(35, 13);
label.TabIndex = 0;
label.Text = label.MoreInfo[0];
}
And later in your event handler you can use the inside information

Sharing a variable between two winforms

I have a winforms application.
I have a textbox on one form (call F1) and when a button is clicked on this form (call F2), it launches another form.
On F2, I want to set a string via a textbox (and save it to a variable in the class), and then when I close this form, the string will appear in a label in F1.
So I am basically sharing variables between both forms. However, I can't get this to work correctly. How would this code look?
I would add a new property to form2. Say it's for a phone number. Then I'd add a friend property m_phone() as string to form 2. After showing an instance of form2 but before closing it, you can refer to the property m_phone in form1's code.
It's an additional level of indirection from Matthew Abbott's solution. It doesn't expose form2 UI controls to form1.
EDIT
e.g.:
public string StoredText
{
get;
private set;
}
inside the set you can refer to your UI control, like return textBox1.text. Use the get to set the textbox value from an earlier load.
And:
public string GetSomeValue()
{
var form = new F2();
form.ShowDialog();
return form.StoredText;
}
Just ensure that StoredText is populated (or not, if appropriate) before the form is closed.
Are you showing the second form as a dialog, this is probably the best way to do it. If you can avoid doing shared variables, you could do the following:
public string GetSomeValue()
{
var form = new F2();
form.ShowDialog();
return form.TextBox1.Text;
}
And called in code:
Label1.Text = GetSomeValue();
This might not be the most efficient way of approaching, but you could create a class called DB (database). Inside this class, create variables like
public static bool test or public static bool[] test = new bool[5];
In your other forms, you can just create an instance. DB db = new DB(); then grab the information using db.test = true/false. This is what I've been doing and it works great.
Sorry, I'm only like a year late.

Categories