If else condition on radio buttons - winforms

I was able to create buttons.I will be using about 65 buttons, how do you use if else condition on the buttons? Can someone please show me an example? Thank you in advance.
private void createButtons()
{
flowLayoutPanel1.Controls.Clear();
for(int i = 0;i <10;i++)
{
RadioButton b = new RadioButton();
b.Name = i.ToString();
b.Text = "radiobutton" + i.ToString();
b.AutoSize = true;
flowLayoutPanel1.Controls.Add(b);
}
}

How about putting the RadioButtons in a list or an array? This way you could use if (allRadioButtons[1].checked) {...}.
Here is an example
private List<RadioButton> allRadioButtons = new List<RadioButton>();
private void createButtons()
{
flowLayoutPanel1.Controls.Clear();
for (int i = 0; i < 10; i++)
{
RadioButton b = new RadioButton();
b.Name = i.ToString();
b.Text = "radiobutton" + i.ToString();
b.AutoSize = true;
flowLayoutPanel1.Controls.Add(b);
//add every button to the list
//the one with the Text radiobutton0 will be accessible as allRadioButtons[0]
//the one with the Text radiobutton1: allRadioButtons[1]
//etc
allRadioButtons.Add(b);
}
}
//you can use your list in any other method
private void myMethod() {
if (allRadioButtons[0].Checked)
{
//do something
}
}

If Andrea's answer didn't work for you (since you didn't mark it as a solution), another option would be to create a container, such as a GroupBox, and then add your programatically created RadioButton controls to this container. Then you can loop over the controls belonging to the GroupBox like this:
foreach (Control c in myGroupBox.Controls)
{
if ((RadioButton)c).Checked)
//Do something
}
This will loop over all the controls in the GroupBox and cast them to a RadioButton and check if they're checked or not. I've used something similar to this as the basis for quite a few requirements in different applications; it's very easy to make a recursive method that takes a ControlCollection, loop over it and apply logic as needed depending on some condition, like the type of control or perhaps the Tag value of the control.
Then as far as adding the RadioButtons to the GroupBox at run time you just do something like myGroupBox.Controls.Add(b) where b is the RadioButton you've created in your for loop in your sample code. More on runtime control creation here.

Related

programatically add button click in winforms?

is it possible to add button click event? i want to add controls dynamicly but i don't bind event's to my controls.
this.buttonDeneme = new System.Windows.Forms.Button();
this.buttonDeneme.Location = new System.Drawing.Point(150, 90);
this.buttonDeneme.Name = "button1";
this.buttonDeneme.Size = new System.Drawing.Size(122, 23);
this.buttonDeneme.TabIndex = 0;
this.buttonDeneme.Text = "FileUpload";
this.buttonDeneme.UseVisualStyleBackColor = true;
this.buttonDeneme.Click += ????
#dotTutorial answer is going to work but lot's people still have difficulty with Linq and Lambda expression so if you don't understand it the very basic way to write this is :
this.buttonDeneme.Click += new EventHandler(MyCustomClickHandler);
void MyCustomClickHandler(object sender, EventArgs e)
{
// do whatever you want here
}
but creating multiple button is usually because they wont do the same exact thing so you might want to set the this.buttonDeneme.Tag to some sort of identifier. i prefer using string in there.
then in the click event you can retrieve that value and know what to do. here a corrected version with the Tag used :
this.buttonDeneme.Tag = "SearchBook";
this.buttonDeneme.Click += new EventHandler(MyCustomClickHandler);
void MyCustomClickHandler(object sender, EventArgs e)
{
// for button created above the value when
// the click is called will be "SearchBook"
string sTag = ((Button)sender).Tag.ToString();
if(sTag == "SearchBook")
{
// do stuff for search book
}
else if(sTag == "blablabla")
{
// do other stuff
}
}
The easiest alternative would be to use a lambda expression.
this.buttonDeneme.Click += ((s, e) => {
// The code that handles a click event
});
's' will be the sender object and 'e' the eventargs.

How to move by code the BindingSource to a specific record

Using datagridview bound to BindingSource control bound to a LINQ to SQL class, I wonder how to position the bindingSource to a specific record, that is, when I type a Product name in a textbox, the bindingsource should move to that specific product. Here is my code:
In my form FrmFind:
NorthwindDataContext dc;
private void FrmFind_Load(object sender, EventArgs e)
{
dc = new NorthwindDataContext();
var qry = (from p in dc.Products
select p).ToList();
FindAbleBindingList<Product> list = new FindAbleBindingList<Product>(qry);
productBindingSource.DataSource = list.OrderBy(o => o.ProductName);
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
TextBox tb = sender as TextBox;
int index = productBindingSource.Find("ProductName", tb.Text);
if (index >= 0)
{
productBindingSource.Position = index;
}
}
In the program class:
public class FindAbleBindingList<T> : BindingList<T>
{
public FindAbleBindingList()
: base()
{
}
public FindAbleBindingList(List<T> list)
: base(list)
{
}
protected override int FindCore(PropertyDescriptor property, object key)
{
for (int i = 0; i < Count; i++)
{
T item = this[i];
//if (property.GetValue(item).Equals(key))
if (property.GetValue(item).ToString().StartsWith(key.ToString()))
{
return i;
}
}
return -1; // Not found
}
}
How can I implement the find method to make it work?
You can combine the BindingSource.Find() method with the Position property.
For example, if you have something like this in your TextBox changed event handler:
private void textBox1_TextChanged(object sender, EventArgs e)
{
TextBox tb = sender as TextBox;
int index = bs.Find("Product", tb.Text);
if (index >= 0)
{
bs.Position = index;
}
}
This of course will depend on a lot of things like the particular implementation of the Find method the data source for the binding source has.
In a question you asked a little while ago I gave you an implementation for Find which worked with full matches. Below is a slightly different implementation that will look at the start of the property being inspected:
protected override int FindCore(PropertyDescriptor property, object key)
{
// Simple iteration:
for (int i = 0; i < Count; i++)
{
T item = this[i];
if (property.GetValue(item).ToString().StartsWith(key.ToString()))
{
return i;
}
}
return -1; // Not found
}
Do note that the above method is case sensitive - you can change StartsWith to be case insensitive if you need.
One key thing to note about the way .Net works is that the actual type of an object is not sufficient all the time - the declared type is what consuming code knows about.
This is the reason why you get a NotSupported exception when calling the Find method, even though your BindingList implementation has a Find method - the code that receives this binding list doesn't know about the Find.
The reason for that is in these lines of code:
dc = new NorthwindDataContext();
var qry = (from p in dc.Products
select p).ToList();
FindAbleBindingList<Product> list = new FindAbleBindingList<Product>(qry);
productBindingSource.DataSource = list.OrderBy(o => o.ProductName);
When you set the data source for the binding source you include the extension method OrderBy - Checking this shows that it returns IOrderedEnumerable, an interface described here on MSDN. Note that this interface has no Find method, so even though the underlying FindableBindingList<T> supports Find the binding source doesn't know about it.
There are several solutions (the best is in my opinion to extend your FindableBindingList to also support sorting and sort the list) but the quickest for your current code is to sort earlier like so:
dc = new NorthwindDataContext();
var qry = (from p in dc.Products
select p).OrderBy(p => p.ProductName).ToList();
FindAbleBindingList<Product> list = new FindAbleBindingList<Product>(qry);
productBindingSource.DataSource = list;
In WinForms there are no entirely out of the box solutions for the things you are trying to do - they all need a little bit of custom code that you need to put together to match just your own requirements.
I took a different approach. I figured, programmatically, every record must be checked until a match is found, so I just iterated using the MoveNext method until I found a match. Unsure if the starting position would be the First record or not, so I used the MoveFirst method to ensure that is was.
There is one assumption, and that is that what you are searching for is unique in that column. In my case, I was looking to match an Identity integer.
int seekID;
this.EntityTableBindingSource.MoveFirst();
if (seekID > 0)
{
foreach (EntityTable sd in EntityTableBindingSource)
{
if (sd.ID != seekID)
{
this.t_EntityTableBindingSource.MoveNext();
}
else
{
break;
}
}
}
I didn't really care for either answer provided. Here is what I came up with for my problem:
// Create a list of items in the BindingSource and use labda to find your row:
var QuickAccessCode = customerListBindingSource.List.OfType<CustomerList>()
.ToList().Find(f => f.QuickAccessCode == txtQAC.Text);
// Then use indexOf to find the object in your bindingSource:
var pos = customerListBindingSource.IndexOf(QuickAccessCode);
if (pos < 0)
{
MessageBox.Show("Could not find " + txtQAC.Text);
}
else
{
mainFrm.customerListBindingSource.Position = pos;
}

Cant see controls inside User Control in the VisualTreeHelper

I have UserControl in wpf 4.0 which contains buttons , labels , textboxes etc....
I want to loop those controls and when I get a buuton , I want to take it's name and save it to my list . Basically , all I want to do is to create a Names_list of all my buttons in the UserControl.
I have a method that iterates all the controls and if it finds a button , it saves it's name -
public void EnumVisual(Visual myVisual)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(myVisual); i++)
{
// Retrieve child visual at specified index value.
Visual childVisual = (Visual)VisualTreeHelper.GetChild(myVisual, i);
Button _button = childVisual as Button;
if (_button != null)
{
Class_Button _newButtonClass = new Class_Button();
if (_button.Name != null)
{
_newButtonClass.ButtonName = _button.Name;
}
ButtonsList.Add(_newButtonClass);
}
// Enumerate children of the child visual object.
EnumVisual(childVisual);
}
}
I always get an empty list.
When I enter in to the code by debugging it and I watch the VisualTree of my UserControl , I see all the Panels and GroupBoxes and Grids but I dont see buttons , labels and texboxes although every control has a x:Name and every control is x:FieldModifier="public". This is very odd....And I cant understand the reason for that as well as how to solve this problem...
can anyone tell what I am doing wrong?
thanks
As suggested by #GazTheDestroyer you want to make sure the control template has been applied before trying to use VisualTreeHelper. Try:
public void EnumVisual(Visual myVisual)
{
if(myVisual is FrameworkElement)
((FrameworkElement)myVisual).ApplyTemplate();
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(myVisual); i++)
{
// Retrieve child visual at specified index value.
Visual childVisual = (Visual)VisualTreeHelper.GetChild(myVisual, i);
Button _button = childVisual as Button;
if (_button != null)
{
Class_Button _newButtonClass = new Class_Button();
if (_button.Name != null)
{
_newButtonClass.ButtonName = _button.Name;
}
ButtonsList.Add(_newButtonClass);
}
// Enumerate children of the child visual object.
EnumVisual(childVisual);
}
}
You can use a tool like Snoop
or WPF Inspector
to examine the visual tree of your control.
If these tools are able to do so, the error must be somewhere in your code, right?

How do I bring an item to the front in wpf?

I simply have two grid on top of one another. Given one state of the world, I want grid A to be on top, given another state of the world, I want grid B to be on top. In the old days we could just call grid.BringToFront(), but that doesn't exist anymore, and I can't figure out any way to make that happen.
The best I can figure, I need to create my own custom classes to allow this functionality, but that seems like major overkill for something that used to be so simple.
You can use the Panel.ZIndex property to change the display order of elements in a panel
You have to use the Z index property, and because there are no built-in function to do what you want, I made my own.
The higher the Z value, the 'closer' to front the control is.
So you want to put your control on top without having to set an arbitrary high Z value.
So here is a small function I wrote for myself to do exactly that.
Note: this assume that you are using a Canvas and UserControls.
So you might need to adapt it a little bit if that's not your case.
Basically it will get the index of the control to move, then any control currently above it will go down by 1 and the control to move will be put on top (to maintain hierarchy).
static public void BringToFront(Canvas pParent, UserControl pToMove)
{
try
{
int currentIndex = Canvas.GetZIndex(pToMove);
int zIndex = 0;
int maxZ = 0;
UserControl child;
for (int i = 0; i < pParent.Children.Count; i++)
{
if (pParent.Children[i] is UserControl &&
pParent.Children[i] != pToMove)
{
child = pParent.Children[i] as UserControl;
zIndex = Canvas.GetZIndex(child);
maxZ = Math.Max(maxZ, zIndex);
if (zIndex > currentIndex)
{
Canvas.SetZIndex(child, zIndex - 1);
}
}
}
Canvas.SetZIndex(pToMove, maxZ);
}
catch (Exception ex)
{
}
}
To whom it may concern:
ZIndex property is 0 by default, so if you have (like me) a Canvas with more than 1 element (>4000 Shapes in my case), all will have ZIndex = 0, so changing the ZIndexes with this method will have no effect.
For this to work, I set the ZIndexes to a known value after creating all the elements, so they can be ordered after.
int zIndex = 0;
for (int i = 0; i < canvas.Children.Count; i++) {
UIElement child = canvas.Children[i] as UIElement;
if (canvas.Children[i] is UIElement) Canvas.SetZIndex(child, zIndex++);
}
Instead of stacking the two grids, change the visibility properties so the grid you aren't using is collapsed.
Expanding on the answer from #PicMickael, this will do exactly as they described but with less instructions:
public void BringToFront<T>(T uiElement, Canvas canvas)
{
try
{
foreach (UIElement s in canvas.Children)
{
Canvas.SetZIndex(s, 1);
}
Canvas.SetZIndex(uiElement as UIElement, 2);
}
catch (Exception ex)
{
WriteLog.Error(ex);
}
}

What is the best way to implement a 2D grid of radio buttons?

What is the best way to implement a 2D grid of radio buttons so that only one option in each column and one option in each row can be selected?
A 1D array of 1D arrays of radio buttons. Each row (or column) would use the normal radio button functionality, while each column (or row) would be updated by a loop called whenever an individual radio button is toggled.
Something like this?
using System;
using System.Drawing;
using System.Windows.Forms;
class Program {
static RadioButton[] bs = new RadioButton[9];
static void HandleCheckedChanged (object o, EventArgs a) {
RadioButton b = o as RadioButton;
if (b.Checked) {
Console.WriteLine(Array.IndexOf(bs, b));
}
}
static void Main () {
Form f = new Form();
int x = 0;
int y = 0;
int i = 0;
int n = bs.Length;
while (i < n) {
bs[i] = new RadioButton();
bs[i].Parent = f;
bs[i].Location = new Point(x, y);
bs[i].CheckedChanged += new EventHandler(HandleCheckedChanged);
if ((i % 3) == 2) {
x = 0;
y += bs[i].Height;
} else {
x += bs[i].Width;
}
i++;
}
Application.Run(f);
}
}
Regards,
tamberg
You could approach this with a custom collection and databind the radio buttons.
Each individual child would have a property for row and a property for column as well as the true/false value flag, which raises an event when changed to true via a click or keypress.
Logic in the collection class would respond to the value change and loop through the other children in the same row and column to notify them that they should be false.
If you don't want to databind, you could also do it with a collection of user controls.

Resources