C# Winforms Treeview Customized Checkboxes - c#

I'm working on a utility that helps me construct long, repetitive HTML tables. I have data imported from an XML file, a listBox that shows the names, buttons that insert text into a richTextBox that contains certain data from the XML, but there's info I have to enter manually for each name.
I have a treeView that lists committees ( parent ) and subcommittees ( 1 level of children ). I can check the appropriate boxes, click a button, and all the corresponding HTML is created. However, each committee ( and sub ) has a chairperson and a ranking member. Instead of adding those two extra nodes under each parent and child - I have 71 parents and children. I'd rather not add 142 more nodes - I'm hoping there's a way to have "four-click" checkboxes...? 1st click = checkmark; 2nd = green; 3rd = red; 4th = cleared. Or similar. That way I could "check" for being a member, "double-check" for Chair, "triple-check" for Ranking, and a fourth would just start over.
I'm open to suggestions for another approach, as well. This is the last bit I need to get working to save me typing 2-3K lines of HTML by hand, so I don't care how I get it done. Thanks.

Okay, sorry it's been a while. You know, life and such. Anyway, I ended up my own TreeNode and TreeView classes. This is my first adventure with WinForms, so a lot of this seemed quite finicky. Ended up be much simpler than I had imagined. If anybody wants to use this, knock yourself out.
The Check*.bmp images are just a checked box that I colored in. I'll probably make my own four images for this and neaten up the populateStateImageList() method. Also, I would think this would work for as many states as you need, up to the 14 image limit of StateImageList.
using System.Drawing;
using System.Windows.Forms;
namespace jkHTMLBuilder
{
public class QuadCheckTreeNode : TreeNode
{
public enum CheckState : int { UnChecked, Checked, Chair, Rank } // The four possible states
private CheckState _cs = CheckState.UnChecked; // The node's current state
public CheckState checkState
{
get
{
return _cs;
}
set
{
_cs = value;
}
}
public QuadCheckTreeNode(string initString) : base()
{
this.Text = initString;
this.checkState = CheckState.UnChecked;
this.Checked = false;
this.StateImageIndex = 0;
}
public void checkAdvance() // This is called from onAfterCheck to set the next consecutive state
{
switch (checkState)
{
case CheckState.UnChecked:
checkState = CheckState.Checked;
break;
case CheckState.Checked:
checkState = CheckState.Chair;
break;
case CheckState.Chair:
checkState = CheckState.Rank;
break;
case CheckState.Rank:
checkState = CheckState.UnChecked;
break;
}
this.Checked = (this.checkState == CheckState.UnChecked ? false : true);
}
}
class QuadCheckTreeView : TreeView
{
private bool clickStop = false;
private bool shouldAdvance = false;
public QuadCheckTreeView() : base()
{
StateImageList = new ImageList();
}
public void populateStateImageList() // I made this a separate method and call it from my Load_Senators method so the images are
{ // set up when the XML file is loaded. Apparently, loading the files ( Check*.bmmp )
for (int i = 0; i < 2; i++) // from the ctor causes problems...? Whatever. This works.
{
Bitmap bmp = new Bitmap(16, 16);
Graphics chkGraphics = Graphics.FromImage(bmp);
switch (i)
{
case 0:
CheckBoxRenderer.DrawCheckBox(chkGraphics, new Point(0, 1), System.Windows.Forms.VisualStyles.CheckBoxState.UncheckedNormal);
break;
case 1:
CheckBoxRenderer.DrawCheckBox(chkGraphics, new Point(0, 1), System.Windows.Forms.VisualStyles.CheckBoxState.CheckedNormal);
break;
}
StateImageList.Images.Add(bmp);
}
Bitmap myBitmap = new Bitmap("..\\..\\CheckBlue.bmp");
StateImageList.Images.Add(myBitmap);
myBitmap = new Bitmap("..\\..\\CheckRed.bmp");
StateImageList.Images.Add(myBitmap);
}
public void ClearNodes(TreeNodeCollection nodes) // This is for when I move on to the next record. Unchecks everything.
{
clickStop = true;
foreach (QuadCheckTreeNode qctn in nodes)
{
qctn.Checked = false;
qctn.checkState = QuadCheckTreeNode.CheckState.UnChecked;
if (qctn.Nodes.Count > 0)
{
foreach (QuadCheckTreeNode cqctn in qctn.Nodes)
{
cqctn.Checked = false;
cqctn.checkState = QuadCheckTreeNode.CheckState.UnChecked;
}
}
}
clickStop = false;
}
protected override void OnCreateControl()
{
base.OnCreateControl();
CheckBoxes = false; // Checkboxes off to use my images
ClearNodes(this.Nodes); // Probably not needed.
}
protected override void OnNodeMouseClick(TreeNodeMouseClickEventArgs e)
{
base.OnNodeMouseClick(e);
TreeViewHitTestInfo tvhtInfo = HitTest(e.X, e.Y); // If you didn't click on it, ignore.
if (tvhtInfo == null || tvhtInfo.Location !=
TreeViewHitTestLocations.StateImage)
{
return;
}
QuadCheckTreeNode qctn = (QuadCheckTreeNode)e.Node; // If you right-clicked, set to UnChecked
if (e.Button == MouseButtons.Right)
{
if (qctn.checkState != QuadCheckTreeNode.CheckState.UnChecked)
{
qctn.checkState = QuadCheckTreeNode.CheckState.UnChecked;
qctn.Checked = false;
shouldAdvance = false;
}
}
else
shouldAdvance = true; // Left click sets this var==true so the node's Advance() method is called
qctn.Checked = qctn.Checked; // This fires the onAfterCheck event
}
protected override void OnAfterCheck(TreeViewEventArgs e)
{
base.OnAfterCheck(e);
if (clickStop) // This keeps the event from running if it's called inappropriately
{
return;
}
clickStop = true;
QuadCheckTreeNode qctn = (QuadCheckTreeNode)e.Node;
if (shouldAdvance)
{
qctn.checkAdvance();
shouldAdvance = false;
qctn.StateImageIndex = (int)qctn.checkState;
}
checkParent(qctn); // Calling this method, if it actually checks a parent node, won't call onAfterCheck because of clickStop
clickStop = false;
}
protected void checkParent(QuadCheckTreeNode qctn)
{
QuadCheckTreeNode pqctn = (QuadCheckTreeNode)qctn.Parent;
if (pqctn == null)
return;
if (pqctn.checkState == QuadCheckTreeNode.CheckState.UnChecked) // This checks a parent if it has a checked child
{
bool chkParent = false;
foreach (QuadCheckTreeNode n in pqctn.Nodes)
{
if (n.checkState != QuadCheckTreeNode.CheckState.UnChecked) // Checks all the children. If even one is checked, the parent gets checked
chkParent = true;
}
if (chkParent)
{
pqctn.Checked = true;
pqctn.checkState = QuadCheckTreeNode.CheckState.Checked;
}
}
}
}
}

Related

in a windows form app when user changes a value after previously setting one, can i update an if statement result?

i have a windows form app (in c#)
with 2 comboboxes, 1 numericUpDown box, 1 textbox.
the user has to choose an input in the first combobox, the second combobox and then choose a value in the numericUpDown.
my program then has to show the result in the textbox.
i used a couple of if statements to display the result.
i know that c# reads the program from top to bottem
and it causes an issue for me.
when the user selects all the options my program will show the correct result, if however the user goes back and changes one of their options, the result is incorrect ( i think it doesn't correctly update the if statement due to c# already being past that part of code?)
i put each if statement in the corresponding "selectedIndexChanged" and "ValueChanged" ( is this the correct way to do it?)
should i use something other than an if statement?
or should i use a "calculate" button, which the user first has to press before showing ANY result?
could i use return or something? i don't really understand those
i tried to set the other bools to false if another one was set to true, but that didn't do anything.
public bool staal = false; //steel
public bool rvs = false; //stainless
public string materiaal;
public void materiaalDropBox_SelectedIndexChanged(object sender, EventArgs e)
{
materiaal = materiaalDropBox.Text; //text currently in combobox
if (materiaal == "Staal")//material = steel
{
staal = true;
rvs = false;
}else if (materiaal == "RVS")
{
rvs = true; // material = stainless
staal = false;
}
}
public string soortboor; //kind of drill
public bool hss = false; //high speed steel drill
public bool hardmetaal = false; //cemented carbide drill
public bool spiraal = false; //basic drill
decimal VC = 0; // 318 * m/ms of drill on material
public void soortBoorDropBox_SelectedIndexChanged(object sender, EventArgs e)
{
soortboor = soortBoorDropBox.Text;// text currently in combobox
if (soortboor == "HSS")
{
hss = true; // drill is high speed steel
hardmetaal = false;
spiraal = false;
}else if (soortboor == "Hardmetaal")
{
hardmetaal = true;// drill is cemented carbide
hss = false;
spiraal = false;
}else if (soortboor == "Spiraal")
{
spiraal = true; // drill is normal
hss = false;
hardmetaal = false;
}
// if material && metal match a certain type, set VC value
if (rvs && hardmetaal)
{
VC = Convert.ToDecimal(318 * 30);
}else if (staal && hardmetaal)
{
VC = Convert.ToDecimal(318 * 60);
}else if (staal && hss)
{
VC = Convert.ToDecimal(318 * 40);
}else if (staal && spiraal)
{
VC = Convert.ToDecimal(318 * 15);
}else
{
VC = 0;
}
}
public decimal diameter; //drill diameter
string RPM; //required RPM ( this is the output we want to calculate)
public void diameterValue_ValueChanged(object sender, EventArgs e)
{
diameter = diameterValue.Value; //get diameter value from numericUpDown
RPM = Convert.ToString(VC / diameter);//convert VC divided by diamter value to string
toerentalValue.Text = RPM; // show RPM value as string in a textbox
}
I don't think it's proper putting all your update code in each selectedIndex_Changed event. Change your code to something like this
public void materiaalDropBox_SelectedIndexChanged(object sender, EventArgs e)
{
//Set your property values
UpdateCalculation();
}
private void UpdateCalculation()
{
//Holds all the other code for calculations
}
So each time a SelectedIndex changes, you just set the value of the comboBox to a private field and then call UpdateCalculations to do the remaining job. UpdateCalculations then gets those values and work on them.

C# - show child control (Listbox) on top of parent control(textbox) in winform

Created a custom intellisense textbox (textbox with listbox a child).
As shown in below image, the listbox pops up when i enter a char which all works fine and good but when i am at the end of textbox the listbox is partially visible, is there anyway i can show the whole listbox content?
Tried this "Show control inside user control outside the boundaries of its parent
But when the popup window opens the text box looses focus and i cannot type anything further, my intellisense textbox keeps giving better results based on what they type but in this situation i am not able to type anymore.
FYI tried to add pParentControl.Focus() into show method defined in other article as shown below, missing something?
public void Show(Control pParentControl)
{
if (pParentControl == null) return;
// position the popup window
var loc = pParentControl.PointToScreen(new Point(0, pParentControl.Height));
pParentControl.Focus();
m_tsdd.Show(loc);
}
Here is the complete code
class TextBox_AutoComplete : TextBox
{
#region Class Members
List<string> dictionary;
ListBox listbox = new ListBox();
#endregion
private PopupHelper m_popup;
#region Extern functions
[DllImport("user32")]
private extern static int GetCaretPos(out Point p);
#endregion
#region Constructors
public TextBox_AutoComplete() : base()
{
this.Margin = new Padding(0, 0, 0, 0);
this.Multiline = true;
this.Dock = DockStyle.Fill;
this.KeyDown += Textbox_KeyDown;
this.KeyUp += Textbox_KeyUp;
listbox.Parent = this;
listbox.KeyUp += List_OnKeyUp;
listbox.Visible = false;
this.dictionary = new List<string>();
}
#endregion
#region Properties
public List<string> Dictionary
{
get { return this.dictionary; }
set { this.dictionary = value; }
}
#endregion
#region Methods
private static string GetLastString(string s)
{
Regex rgx = new Regex("[^a-zA-Z0-9_.\\[\\]]");
s = rgx.Replace(s, " ");
string[] strArray = s.Split(' ');
return strArray[strArray.Length - 1];
}
protected override void OnTextChanged(EventArgs e)
{
base.OnTextChanged(e);
Point cp;
GetCaretPos(out cp);
List<string> lstTemp = new List<string>();
List<string> TempFilteredList = new List<string>();
string LastString = GetLastString(this.Text.Substring(0, SelectionStart));
//MessageBox.Show(LastString);
/*seperated them so that column name matches are found first*/
TempFilteredList.AddRange(dictionary.Where(n => n.Replace("[", "").ToUpper().Substring(n.IndexOf(".") > 0 ? n.IndexOf(".") : 0).StartsWith(LastString.ToUpper())
).Select(r => r)
.ToList());
TempFilteredList.AddRange(dictionary.Where(n => n.Replace("[", "").ToUpper().StartsWith(LastString.ToUpper())
|| n.ToUpper().StartsWith(LastString.ToUpper()))
.Select(r => r)
.ToList());
lstTemp = TempFilteredList.Distinct().Select(r => r).ToList();
/*Getting max width*/
int maxWidth = 0, temp = 0;
foreach (var obj in lstTemp)
{
temp = TextRenderer.MeasureText(obj.ToString(), new Font("Arial", 10, FontStyle.Regular)).Width;
if (temp > maxWidth)
{
maxWidth = temp;
}
}
listbox.SetBounds(cp.X + 20, cp.Y + 20, maxWidth, 60);
if (lstTemp.Count != 0 && LastString != "")
{
listbox.DataSource = lstTemp;
// listbox.Show();
if (m_popup == null)
m_popup = new PopupHelper(listbox);
m_popup.Show(this);
}
else if (m_popup != null)
{
//listbox.Hide();
m_popup.Hide();
}
}
protected void Textbox_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Down)
{
if (listbox.Visible == true)
{
listbox.Focus();
}
e.Handled = true;
}
else if (e.KeyCode == Keys.Escape)
{
listbox.Visible = false;
e.Handled = true;
}
}
protected void Textbox_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Space && listbox.Visible == true)
{
listbox.Focus();
List_OnKeyUp(listbox, new KeyEventArgs(Keys.Space));
e.Handled = true;
}
if (e.KeyCode == Keys.Down && listbox.Visible == true)
{
listbox.Focus();
e.Handled = true;
}
}
private void List_OnKeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Space || e.KeyCode == Keys.Enter)
{
int Selection_Start = this.SelectionStart;
string StrLS = GetLastString(this.Text.Substring(0, Selection_Start));
this.Select(Selection_Start - StrLS.Length, StrLS.Length);
// MessageBox.Show(this.Selection_Start.ToString() + " Last string" + StrLS);
this.SelectedText=((ListBox)sender).SelectedItem.ToString();
listbox.Hide();
this.Focus();
}
}
#endregion
}
public sealed class PopupHelper : IDisposable
{
private readonly Control m_control;
private readonly ToolStripDropDown m_tsdd;
private readonly Panel m_hostPanel; // workarround - some controls don't display correctly if they are hosted directly in ToolStripControlHost
public PopupHelper(Control pControl)
{
m_hostPanel = new Panel();
m_hostPanel.Padding = Padding.Empty;
m_hostPanel.Margin = Padding.Empty;
m_hostPanel.TabStop = false;
m_hostPanel.BorderStyle = BorderStyle.None;
m_hostPanel.BackColor = Color.Transparent;
m_tsdd = new ToolStripDropDown();
m_tsdd.CausesValidation = false;
m_tsdd.Padding = Padding.Empty;
m_tsdd.Margin = Padding.Empty;
m_tsdd.Opacity = 0.9;
m_control = pControl;
m_control.CausesValidation = false;
m_control.Resize += MControlResize;
//m_hostPanel.Controls.Add(m_control);
m_tsdd.Padding = Padding.Empty;
m_tsdd.Margin = Padding.Empty;
m_tsdd.MinimumSize = m_tsdd.MaximumSize = m_tsdd.Size = pControl.Size;
m_tsdd.Items.Add(new ToolStripControlHost(m_control));
}
private void ResizeWindow()
{
m_tsdd.MinimumSize = m_tsdd.MaximumSize = m_tsdd.Size = m_control.Size;
m_hostPanel.MinimumSize = m_hostPanel.MaximumSize = m_hostPanel.Size = m_control.Size;
}
private void MControlResize(object sender, EventArgs e)
{
ResizeWindow();
}
/// <summary>
/// Display the popup and keep the focus
/// </summary>
/// <param name="pParentControl"></param>
public void Show(Control pParentControl)
{
if (pParentControl == null) return;
// position the popup window
var loc = pParentControl.PointToScreen(new Point(0, pParentControl.Height));
pParentControl.Focus();
m_tsdd.Show(loc);
}
public void Hide()
{
m_tsdd.Hide();
}
public void Close()
{
m_tsdd.Close();
}
public void Dispose()
{
m_control.Resize -= MControlResize;
m_tsdd.Dispose();
m_hostPanel.Dispose();
}
}
Firstly, I personally don't see any benefit in having a control inside another. Yes, the child control is locked inside its parent's boundaries automatically for you, but this benefit is negated by the issue that you're facing, and solving that issue requires the same work as when the two controls have no relation. In both cases, you'll have to do the calculations manually to keep the child visible inside its parent. In the second case the parent is the app's window.
Secondly, I don't recommend using hacks like the one mentioned in the comments to show the child outside its parent's boundaries. The hack creates more issues than it solves, as you found out. And what's the point of that hack anyway? If you want to show the child outside the parent, then don't make it a child control in the first place, and you don't need any hack.
The best solution is the one that you find in any well designed app, and in Windows itself. Open any app, let's say Notepad, and right-click near the upper-left corner. You'll see the context menu pulling to lower-right direction. Now right-click near the other three corners and you'll see the context menu pulling in different direction each time, so it will always be visible inside the app. Now if you resize the app window too small and right-click, the context menu will choose the best direction but some of it will be outside the app because the window is too small. That's why you need your list not to be a child, but it's up to you, and it's only about these edge cases. The solution will be similar in both cases.
You're displaying the list in this line:
listbox.SetBounds(cp.X + 20, cp.Y + 20, maxWidth, 60);
The key is cp.X and cp.Y. This is what decides where the list will appear. You need to make this point dynamic and responsive to the boundaries of the parent. You fixed the width to maxWidth and height to 60, so I will use those values in the calculation.
To make sure the list will not go beyond the bottom:
var y = this.Height < cp.Y + 60 ? this.Height - 60 : cp.Y;
To make sure the list will not go beyond the right:
var x = this.Width < cp.X + maxWidth ? this.Width - maxWidth : cp.X;
Now you can show your list at the calculated point:
listbox.SetBounds(x, y, maxWidth, 60);
Notes:
I didn't include the 20 gap that you used. I think it looks better without the gap and I haven't seen any app that has a gap. If you prefer the gap, add it to the calculation of x and y. Don't add it in the SetBounds() or that will screw up the calculation.
The calculation above doesn't take into account when the parent size is too small to show the child inside. If you want to support that edge case, you need to make the child a separate control and add some checks to the calculation.

Check Box react as Radio Button using C#

I have one requirement to add three check box in a group box, and check-box must react as radio button i.e.,
1. one can check only one check-box at a time.
2. when user goes to check another check box, previous one automatically should be unchecked.
I also know that this is not a good approach to do this, and it's really confusing to non-technical or technical user but I also want to learn something new in this.
I went through lots of sites, but I didn't get any satisfactory solution. I hope I will get good one from you.
Moreover, There are simple three check box to indicate three things for selection respectively and one text box. If one checks anyone things then texbox shows the selected thing.
For example:- Check-box show C#,ASP.NET and MVC respectively.
If one select C# then text-box must show C#.
Thanks...
With Thanks and Regards,
Ravindra.
You can use radio button for this functionality.
I'd do it like this, assuming you use winforms:
public partial class Form1 : Form
{
private bool ignoreEvents = false;
public Form1()
{
InitializeComponent();
//set this handler to the events of all 3 checkboxes
checkBox1.CheckedChanged += radioCheckboxes_CheckedChanged;
checkBox2.CheckedChanged += radioCheckboxes_CheckedChanged;
checkBox3.CheckedChanged += radioCheckboxes_CheckedChanged;
}
private void radioCheckboxes_CheckedChanged(object sender, EventArgs e)
{
if (!ignoreEvents)
{
ignoreEvents = true; // otherwise the other checkboxes would react when i set the state programmatically
CheckBox current = sender as CheckBox;
if (current == checkBox1)
{
checkBox2.Checked = false;
checkBox3.Checked = false;
}
else if (current == checkBox2)
{
checkBox1.Checked = false;
checkBox3.Checked = false;
}
else
{
checkBox1.Checked = false;
checkBox2.Checked = false;
}
ignoreEvents = false;
}
}
}
With WPF I'd just use a style for a radiobutton so that it looks like a checkbox...
you can simply use another task like timer that updates every 50ms ,
so as to disable the check boxes you want to disable there ,
in your "checked changed event" only flag the controls ,
like for checkbox1 = flagdcheckbx = 1 ; and so on.
private async Task writeTimer()
{
if(ignoreEvents == true)
{
ignoreEvents = false;
switch(flagdcheckbx)
{
case 1:
checkBox2.Checked = false;
checkBox3.Checked = false;
break;
case 2:
checkBox1.Checked = false;
checkBox3.Checked = false;
break;
case 3:
checkBox1.Checked = false;
checkBox2.Checked = false;
break;
}
}
}
private void radioCheckboxes_CheckedChanged(object sender, EventArgs e)
{
CheckBox current = sender as CheckBox;
if (current == checkBox1)
{
if (current.checked)
{
ignoreEvents = true;
flagdcheckbx=1;
}
}
else if (current == checkBox2)
{
if (current.checked) // it should happen only when checked
{
ignoreEvents = true;
flagdcheckbx=2;
}
}
else
{
if (current.checked)
{
ignoreEvents = true;
flagdcheckbx=3;
}
}
}
I assume you know how to group RadioButton controls inside a container and you just look for the CheckBox appearance for your radio button groups.
As an option you can modify the RadioButtonList that I've shared in [this post] and add the CheckBox appearance to it. In the following picture you can see two RadioButtonList control, one with CheckBox appearance and the other with RadioButton appearance:
radioButtonList1.DataSource = Enum.GetValues(typeof(DayOfWeek));
radioButtonList1.Appearance = RadioButtonListAppearance.CheckBox;
radioButtonList2.DataSource = Enum.GetValues(typeof(DayOfWeek));
Here is the modified version of code to add Appearance property:
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
public class RadioButtonList : ListBox
{
RadioButtonListAppearance appearance = RadioButtonListAppearance.RadioButton;
public RadioButtonListAppearance Appearance
{
get { return appearance; }
set { appearance = value; Invalidate(); }
}
Size s;
public RadioButtonList()
{
this.DrawMode = DrawMode.OwnerDrawFixed;
using (var g = Graphics.FromHwnd(IntPtr.Zero))
s = RadioButtonRenderer.GetGlyphSize(
Graphics.FromHwnd(IntPtr.Zero), RadioButtonState.CheckedNormal);
}
protected override void OnDrawItem(DrawItemEventArgs e)
{
var text = (Items.Count > 0) ? GetItemText(Items[e.Index]) : Name;
Rectangle r = e.Bounds; Point p;
var flags = TextFormatFlags.Default | TextFormatFlags.NoPrefix;
var selected = (e.State & DrawItemState.Selected) == DrawItemState.Selected;
var state = selected ?
(Enabled ? RadioButtonState.CheckedNormal :
RadioButtonState.CheckedDisabled) :
(Enabled ? RadioButtonState.UncheckedNormal :
RadioButtonState.UncheckedDisabled);
if (RightToLeft == System.Windows.Forms.RightToLeft.Yes)
{
p = new Point(r.Right - r.Height + (ItemHeight - s.Width) / 2,
r.Top + (ItemHeight - s.Height) / 2);
r = new Rectangle(r.Left, r.Top, r.Width - r.Height, r.Height);
flags |= TextFormatFlags.RightToLeft | TextFormatFlags.Right;
}
else
{
p = new Point(r.Left + (ItemHeight - s.Width) / 2,
r.Top + (ItemHeight - s.Height) / 2);
r = new Rectangle(r.Left + r.Height, r.Top, r.Width - r.Height, r.Height);
}
var bc = selected ? (Enabled ? SystemColors.Highlight :
SystemColors.InactiveBorder) : BackColor;
var fc = selected ? (Enabled ? SystemColors.HighlightText :
SystemColors.GrayText) : ForeColor;
using (var b = new SolidBrush(bc))
e.Graphics.FillRectangle(b, e.Bounds);
if (appearance == RadioButtonListAppearance.RadioButton)
{
RadioButtonRenderer.DrawRadioButton(e.Graphics, p, state);
}
else if (appearance == RadioButtonListAppearance.CheckBox)
{
CheckBoxRenderer.DrawCheckBox(e.Graphics, p, (CheckBoxState)state);
}
else
{
throw new InvalidOperationException("Appearance is invalid.");
}
TextRenderer.DrawText(e.Graphics, text, Font, r, fc, bc, flags);
e.DrawFocusRectangle();
base.OnDrawItem(e);
}
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override SelectionMode SelectionMode
{
get { return System.Windows.Forms.SelectionMode.One; }
set { }
}
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override int ItemHeight
{
get { return (this.Font.Height + 2); }
set { }
}
[EditorBrowsable(EditorBrowsableState.Never), Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override DrawMode DrawMode
{
get { return base.DrawMode; }
set { base.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed; }
}
}
public enum RadioButtonListAppearance
{
RadioButton,
CheckBox
}
Assuming you have a few CheckBox controls in a container like a GroupBox, In the load event of your form:
Find all CheckBox controls of the container
Set AutoCheck property of the CheckBox controls to false
Handle Click event of the CheckBox controls and in the event handler, set Checked property of clicked element to true and for rest, set it to false
Here is the code:
private void Form1_Load(object sender, EventArgs e)
{
var all = groupBox1.Controls.OfType<CheckBox>().ToList();
foreach (CheckBox c in all)
{
c.AutoCheck = false;
c.Click += (obj, args) =>
{
var ThisCheckBox = (CheckBox)obj;
foreach( CheckBox cc in all.Except(new[] { ThisCheckBox }))
cc.Checked = false;
ThisCheckBox.Checked = true;
};
}
}

How to search for two similar images (memory game)

i try to search for 2 similar images (like in a memory game)
i know how to do it, but it for sure is not the best way i guess...
anyone has a better solution?
here is the code how i have done it
private void first_button (object sender, System.Windows.Input.GestureEventArgs e) //so button get pressed
{
field_one = true;
StoryboardBack11.Begin();
StoryboardBack11.Completed += new EventHandler(AfterAnimation);
i = i + 1;
}
// same for the other buttons
private void AfterAnimation(object sender, EventArgs e) //check here after storyboard completed
{if (i == 2) // check after 2 clicks
{
i = 0;
if (field_one == true && field_two == true)
{
if (imageUri_one.Equals(imageUri_two))
{
Fade_one.Begin(); //Storyboard starts
Fade_two.Begin();
field_one = false;
field_two = false;
}
}
//and this for every possible combination
//-> here is my problem because it is a lot to copy paste and thus not optimal i guess
if (field_one == true && field_three == true)
{
if (imageUri_one.Equals(imageUri_three))
{
Fade_one.Begin();
Fade_three.Begin();
field_one = false;
field_three = false;
}
}
// here is the shuffeling of the images
private void test1(object sender, System.Windows.Input.GestureEventArgs e)
{
List<string> Test = new List<string>(); //list of the images
Test.Add("Art1.png");
Test.Add("Art1.png");
Test.Add("Art2.png");
Test.Add("Art2.png");
Test.Add("Art3.png");
Test.Add("Art3.png");
Test.Shuffle(); //they get randomly shuffled here and then realigned
imageUri_one = Test[0];
imageUri_two = Test[1];
imageUri_three = Test[2];
// ..... and so on
// put the new image Uri to a button -> the same 6 time for everey button
BitmapImage bm_one = new BitmapImage(new Uri(#imageUri_one, UriKind.RelativeOrAbsolute));
image11.Source = bm_one; //but it in xaml Source
}
so the thing is that i want to make the Uri flexible, so that i can shuffle different Uri when using another list and this should already work. but is there a more elegant way to check for similar images?
hope the question is clear :)
Pseudo-code:
public class MyElement
{
public bool IsPressed { get; set; }
public string Uri { get; set; }
... anything else you want to know about that one tile
}
then build the logical board
MyElement[,] tiles = new MyElement[8, 8];
for(int i = 0; i < 8; i++)
{
for(j = 0; j < 8; j++)
{
tiles[i, j] = new MyElement { IsPressed = false; Uri = whatever; ... };
}
}
Now create the "physical" board with the buttons and assign a custom value for all buttons which contains it's coordinates.
Create one click handler where you check the tiles array for that coordinate and check it's MyElement object. Assign this click handler to all button click event.

Toolstrip with check button group

I'd like to have a toolstrip with some buttons on it (WinFroms/c#/.net4). I'd like to have the clicked button be checked and all others unchecked, so I want to have only the clicked button checked, all the others unchecked.
I know toolstrip button has checkedonlclick property, but when I click one button, others may be also checked. In good old VB6 there was an automatic solution for this problem: buttongroup on toolbar. Is there any similar in Winfoms?
Or should I handle it from code?! Switch all other buttons to unchecked state when one button is checked? If so, then it would not be my favourite solution...
Call this code on the toolStripButton_Click events and you should get the desired result.
foreach (ToolStripButton item in ((ToolStripButton)sender).GetCurrentParent().Items)
{
if (item == sender) item.Checked = true;
if ((item != null) && (item != sender))
{
item.Checked = false;
}
}
I guess this is an old question, however I was looking for a solution to this problem as well and ended up making a kind of ToolStripRadioButton by extending ToolStripButton. The behaviour should be the same as a normal radio button, as far as I can see. I have however added a group id to make it possible to have multiple radio button groups within the same toolstrip.
One can add the radio button to a toolstrip like a normal ToolStripButton:
To make the button stand more out when checked I have given it a gradient background (CheckedColor1 to CheckedColor2 from top to bottom):
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Windows.Forms;
public class ToolStripRadioButton : ToolStripButton
{
private int radioButtonGroupId = 0;
private bool updateButtonGroup = true;
private Color checkedColor1 = Color.FromArgb(71, 113, 179);
private Color checkedColor2 = Color.FromArgb(98, 139, 205);
public ToolStripRadioButton()
{
this.CheckOnClick = true;
}
[Category("Behavior")]
public int RadioButtonGroupId
{
get
{
return radioButtonGroupId;
}
set
{
radioButtonGroupId = value;
// Make sure no two radio buttons are checked at the same time
UpdateGroup();
}
}
[Category("Appearance")]
public Color CheckedColor1
{
get { return checkedColor1; }
set { checkedColor1 = value; }
}
[Category("Appearance")]
public Color CheckedColor2
{
get { return checkedColor2; }
set { checkedColor2 = value; }
}
// Set check value without updating (disabling) other radio buttons in the group
private void SetCheckValue(bool checkValue)
{
updateButtonGroup = false;
this.Checked = checkValue;
updateButtonGroup = true;
}
// To make sure no two radio buttons are checked at the same time
private void UpdateGroup()
{
if (this.Parent != null)
{
// Get number of checked radio buttons in group
int checkedCount = this.Parent.Items.OfType<ToolStripRadioButton>().Count(x => x.RadioButtonGroupId == RadioButtonGroupId && x.Checked);
if (checkedCount > 1)
{
this.Checked = false;
}
}
}
protected override void OnClick(EventArgs e)
{
base.OnClick(e);
this.Checked = true;
}
protected override void OnCheckedChanged(EventArgs e)
{
if (this.Parent != null && updateButtonGroup)
{
foreach (ToolStripRadioButton radioButton in this.Parent.Items.OfType<ToolStripRadioButton>())
{
// Disable all other radio buttons with same group id
if (radioButton != this && radioButton.RadioButtonGroupId == this.RadioButtonGroupId)
{
radioButton.SetCheckValue(false);
}
}
}
}
protected override void OnPaint(PaintEventArgs e)
{
if (this.Checked)
{
var checkedBackgroundBrush = new LinearGradientBrush(new Point(0, 0), new Point(0, this.Height), CheckedColor1, CheckedColor2);
e.Graphics.FillRectangle(checkedBackgroundBrush, new Rectangle(new Point(0, 0), this.Size));
}
base.OnPaint(e);
}
}
Perhaps useful to others as well.
I'm not aware of a way to do this in the designer, but it's fairly simple to do in code:
readonly Dictionary<string, HashSet<ToolStripButton>> mButtonGroups;
...
ToolStripButton AddGroupedButton(string pText, string pGroupName) {
var newButton = new ToolStripButton(pText) {
CheckOnClick = true
};
mSomeToolStrip.Items.Add(newButton);
HashSet<ToolStripButton> buttonGroup;
if (!mButtonGroups.TryGetValue(pGroupName, out buttonGroup)) {
buttonGroup = new HashSet<ToolStripButton>();
mButtonGroups.Add(pGroupName, buttonGroup);
}
newButton.Click += (s, e) => {
foreach (var button in buttonGroup)
button.Checked = button == newButton;
};
return newButton;
}
I haven't done it in a little but if you use a group box around radio buttons it will only allow one to be checked at a time.

Categories

Resources