How to disable a checkbox in a checkedlistbox? - c#

I have some items in a CheckedListBox, I want to disable the CheckBox of first item in it.
i.e. I want to disable the first item in the CheckedListBox, because I want to tell the user visually that option is not available.

Combining 2 of the above partial answers worked great for me.
Add your items to the list with:
myCheckedListBox.Items.Add(myItem, myState);
Where myState is CheckState.Indeterminate for items that should be disabled.
Then add an event handler to keep those items from being changed:
myCheckedListBox.ItemCheck += (s, e) => { if (e.CurrentValue == CheckState.Indeterminate) e.NewValue = CheckState.Indeterminate; };
This does not allow you to use 'Indeterminate' in this list for its normal purpose but it does give a look very similar to what one would expect for a disabled item and it provides the correct behavior!

Though this post is pretty old, the last added answer has been submitted in April this year,
and I hope this will help someone.
I was after something similar : a checked list box that behaves like
a lot of installers, which offer a list of options where some features are required and
thus are both checked and disabled.
Thanks to this post (Can I use a DrawItem event handler with a CheckedListBox?)
I managed to do that, subclassing a CheckedListBox control.
As the OP in the linked post states, in the CheckedListBox control the OnDrawItem event is never fired,
so subclassing is necessary.
It's very basic, but it works.
This is what it looks like (the CheckBox above is for comparison) :
NOTE: the disabled item is really disabled : clicking on it has no effects whatsoever (as far as I can tell).
And this is the code :
public class CheckedListBoxDisabledItems : CheckedListBox {
private List<string> _checkedAndDisabledItems = new List<string>();
private List<int> _checkedAndDisabledIndexes = new List<int>();
public void CheckAndDisable(string item) {
_checkedAndDisabledItems.Add(item);
this.Refresh();
}
public void CheckAndDisable(int index) {
_checkedAndDisabledIndexes.Add(index);
this.Refresh();
}
protected override void OnDrawItem(DrawItemEventArgs e) {
string s = Items[e.Index].ToString();
if (_checkedAndDisabledItems.Contains(s) || _checkedAndDisabledIndexes.Contains(e.Index)) {
System.Windows.Forms.VisualStyles.CheckBoxState state = System.Windows.Forms.VisualStyles.CheckBoxState.CheckedDisabled;
Size glyphSize = CheckBoxRenderer.GetGlyphSize(e.Graphics, state);
CheckBoxRenderer.DrawCheckBox(
e.Graphics,
new Point(e.Bounds.X + 1, e.Bounds.Y + 1), // add one pixel to align the check gliph properly
new Rectangle(
new Point(e.Bounds.X + glyphSize.Width + 3, e.Bounds.Y), // add three pixels to align text properly
new Size(e.Bounds.Width - glyphSize.Width, e.Bounds.Height)),
s,
this.Font,
TextFormatFlags.Left, // text is centered by default
false,
state);
}
else {
base.OnDrawItem(e);
}
}
public void ClearDisabledItems() {
_checkedAndDisabledIndexes.Clear();
_checkedAndDisabledItems.Clear();
this.Refresh();
}
}
Use it like this:
checkedListBox.Items.Add("Larry");
checkedListBox.Items.Add("Curly");
checkedListBox.Items.Add("Moe");
// these lines are equivalent
checkedListBox.CheckAndDisable("Larry");
checkedListBox.CheckAndDisable(0);
Hope this can help someone.

Disabling items isn't a great idea, the user will have no good feedback that click the check box won't have any effect. You cannot use custom drawing to make it obvious. Best thing to do is to simply omit the item.
You can however easily defeat the user with the ItemCheck event:
private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e) {
if (e.Index == 0) e.NewValue = e.CurrentValue;
}

To disable any particular item use following:
checkedListBox1.SetItemCheckState(0, CheckState.Indeterminate);
SetItemCheckState takes index of item and CheckState Enum
Indeterminate is used to show shaded appearance

I know it has been a while, but I found this in my search for a list box and thought I would add it to the discussion.
If you have a listbox and want to disable all of the checkboxes so they cannot be clicked, but not disable the control so the user can still scroll etc. you can do this:
listbox.SelectionMode = SelectionMode.None

The CheckedListBox will not work in this way. CheckedListBox.Items is a collection of strings so they cannot be "disabled" as such.
Here are some discussions about possible solutions that might help you: here and here.

This works for me:
checkedListBox1.SelectionMode = SelectionMode.None;
Which means no items can be selected
None: No items can be selected.
For more info, you can check it here: SelectionMode Enumeration.

The solution is to use the event ItemChecking:
_myCheckedListBox.ItemChecking += (s, e) => e.Cancel = true;
This will cancel all the checking on every item, but you can always do more refined solution but testing the current .SelectedItem

Here's how I did it in a helpdesk application I wrote:
First, I made it so the check box was greyed out as I added it to the list during form load:
private void frmMain_Load(object sender, EventArgs e)
{
List<string> grpList = new List<string>();
ADSI objADSI = new ADSI();
grpList = objADSI.fetchGroups();
foreach (string group in grpList)
{
if (group == "SpecificGroupName")
{
chkLst.Items.Add(group, CheckState.Indeterminate);
}
else
{
chkLst.Items.Add(group);
}
}
Then I used an event so that when clicked it ensures it stays clicked:
private void chkLst_SelectedIndexChanged(object sender, EventArgs e)
{
if (chkLst.SelectedItem.ToString() == "SpecificGroupName")
{
chkLst.SetItemCheckState(chkLst.SelectedIndex, CheckState.Indeterminate);
}
}
The idea here is that on my form it's set so that the box checks on item click/select. This way I could kill two birds with one stone. I could keep this event from causing problems when the item is first checked and added during form load. Plus making it check on select allows me to use this event instead of the item checked event. Ultimately the idea is to keep it from messing up during the load.
You'll also notice that it doesn't matter what the index number is, that variable is unknown because in my app it's grabbing a list of groups from AD that exist in a specific OU.
As to whether this is a good idea or not, that's dependent on the situation. I have another app where the item to disable is dependent on another setting. In this app I just want the helpdesk to see that this group is required so they don't go removing them from it.

Try Below Code:
Private Sub CheckedListBox1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles CheckedListBox1.MouseUp
If (Condition) Then
Me.CheckedListBox1.SelectedIndex = -1
End If
End Sub

I think an alternative solution, is using Telerik components.
A RadListControl can give you that option:

Related

TabControl AddingTab event

I have a TabControl in which I want to prevent adding existing TabPage (they are identified by a name) and instead set the SelectedTabPage to this precise tab.
I wish to know if there are an event that triggers right before a page is being added to the TabControl. If not, would using the event CollectionChanged of the TabPages (list) be a correct alternative ?
I believe the event you're looking for is the Control.ControlAdded event:
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.controladded.aspx
If that also detects when things inside the tab pages themselves are added, you should be able to filter out everything but TabPage controls using the ControlEventArgs.Control property in your event handler.
To reject adding a control will be a little more complicated. Since this event seems to only be raised after the control gets added, you'll need to do something like this:
void onControlAdded(object sender, ControlEventArgs e) {
var tab = e as TabPage;
if (tab == null)
return;
this.myTabControlObject.TabPages.Remove(tab);
}
This should remove the tab, but it will likely slow the tab adding process considerably.
Try something like this, I am checking the TabControl page Collection for a page with the same name as the Page that is trying to be added, if it exists I am setting focus to the existing instance, otherwise adding the new page to the TabControl. See if something like this works for you.
private void button1_Click(object sender, EventArgs e)
{
TabPage tp = new TabPage();
tp.Name = tabPage1.Name;
var temp =tabControl1.Controls.Find(tp.Name,true);
if( temp.Length > 0)
{
tabControl1.SelectedTab = (TabPage) temp[0];
}
else
tabControl1.Controls.Add(tp);
}
Anything having to do with the ControlCollection will most likely be triggered after the control has been added.
From above link:
You can determine if a Control is a member of the collection by passing the control into the Contains method. To get the index value of the location of a Control in the collection, pass the control into the IndexOf method. The collection can be copied into an array by calling the CopyTo method.
If you want you could cleanup your code some by adding an ExtensionMethod to your TabControl Check for an existing page, set focus or add from there.
Example:
namespace ExtensionMethods
{
public static class MyExtensions
{
public static bool AddPage(this TabControl tc, TabPage tp)
{
var matchedPages = tc.Controls.Find(tp.Name, false);
if ( matchedPages.Length > 0)
{
tc.SelectedTab = (TabPage)matchedPages[0];
return true;
}
else
{
tc.TabPages.Add(tp);
tc.SelectedTab = tp;
return false;
}
}
}
}
Usage:
tabControl1.AddPage(tp);

Jumping to next tab

I have a tab control in my WPF application with multiple tabs. Each tab gives access to several buttons, text boxes, drop downs. Now before moving to the next tab valid entries in each of the controls in the tab is to be checked or jumping to the next tab should not be allowed. How can this be done?
I was able to use IsEnable property to do this. But I want it like, when I click on the next tab it should, without entering the next tab, display a warning that such and such entry in the present tab is not valid.
If you adhere to the Selected event you can do something like this:
// Keep a global variable for the previous index
int prevIndex = 0;
private void tabControl_Selected(object sender, TabControlEventArgs e)
{
TabControl tc = sender as TabControl;
if (tc != null)
{
bool letSwitchHappen = validateTabControls(tc.SelectedIndex);
if (!letSwitchHappen)
{
tc.SelectedIndex = prevIndex;
}
prevIndex = tc.SelectedIndex;
}
}
Where validateTabControls is something like:
private bool validateTabControls(int tabIndex)
{
bool validEntries = false;
// Some code here to set validEntries according to the control at tabIndex
return validEntries;
}
Take a look at this example from Josh Smith.
It shows explicitly how to do this, and Josh is well-known (and respected) in the WPF world.

Overriding OnDoubleClick() event on a List View

I have a MyListView class that is inheriting from ListView, and is overriding OnDragDrop() (and the other necessary events to implement drag and drop). When I place two of these MyListviews on a form I am able to drag an item from one of them and drop it to the other one. This part works.
Now I want to override OnDoubleClick() to that class such that again if I place two of these MyListViews on a form and double clicked on one of them, the item gets removed from that and gets added to the other one. But I can't get my head around how to do this one.
Could you please give me some ideas? Thanks.
Don't know if you manage the sleection of the item in a particular way, but you can
or after handling double-click look for SelectedItems and act on it
or you can add a code like this using ListViewHitTestInfo class:
private override OnDoubleClick(...)
{
ListViewHitTestInfo hit = this.HitTest(e.Location);
if (hit.Item != null)
{
ListViewItem doubleClickedItem = hit.Item;
}
}
Put the logic in your host form by:
Handle double-click of first ListView
Remove from first ListView
Add to second ListView
Unless you are doing this in many different forms - it's not worth complicating it more than that.
EDIT:
If justified, centralizing can be as easy as adding a method which does the same thing (pseudocode)
public void MyForm_OnListViewDoubleClick(object sender, EventArgs e)
{
MoveListItem(firstListView, secondListView);
}
// ...
public static void MoveListItem(ListView source, ListView destination)
{
var listItem = source.SelectedItem;
source.Remove( listItem );
destination.Add( listItem );
}
Here's the answer to your title
protected override void OnDoubleClick(EventArgs e)
{
base.OnDoubleClick(e);
}
And here is the answer to your question
Using DoubleClick event on a inherited class from ListView
This just links back to your other, very similar question.

WP7 Auto Grow ListBox upon reaching the last item

I'm trying to achieve an effect where more items are appended to the list when the user scrolls down to the last item. I haven't found a way to determine if the user has scrolled to the end of the list. I don't see a event on ListBox that is fired when the user reaches the bottom of the list. Something that tells me when an item has been scrolled into view would be great, but as far as I can tell, there is nothing like that.
Is this even possible in WP7?
Edit: Another way of saying this is, can we detect when a list has "bounced"?
Daniel Vaughan has posted an example of how to detect for this at http://danielvaughan.orpius.com/post/Scroll-Based-Data-Loading-in-Windows-Phone-7.aspx
It isn't super easy to get going since there are a lot of moving parts, but here is what you can do, assuming you want a short list that loads more from your data as you get scrolling down, similar to a lot of twitter apps, etc.
Write your own subclass of ObservableCollection that only offers up a few items (like 20), keeping the rest held back until requested
Hook up to the scroll viewer (inside the listbox or container) and its visual state changed events, you can get the NotScrolling and Scrolling changes; for an example see this code by ptorr
When scrolling stops, use viewer scroll extensions code to see where things are extended (at the bottom or not) or just the raw scroll viewer properties to see if it is extended to the bottom
If so, trigger your observable collection to release another set of items.
Sorry I don't have a complete sample ready to blog yet. Good luck!
I've just implemented this for Overflow7.
The approach I took was similar to http://blog.slimcode.com/2010/09/11/detect-when-a-listbox-scrolls-to-its-end-wp7/
However, instead of using a Style I did the hook up in code.
Basically derived my parent UserControl from:
public class BaseExtendedListUserControl : UserControl
{
DependencyProperty ListVerticalOffsetProperty = DependencyProperty.Register(
"ListVerticalOffset",
typeof(double),
typeof(BaseExtendedListUserControl),
new PropertyMetadata(new PropertyChangedCallback(OnListVerticalOffsetChanged)));
private ScrollViewer _listScrollViewer;
protected void EnsureBoundToScrollViewer()
{
if (_listScrollViewer != null)
return;
var elements = VisualTreeHelper.FindElementsInHostCoordinates(new Rect(0,0,this.Width, this.Height), this);
_listScrollViewer = elements.Where(x => x is ScrollViewer).FirstOrDefault() as ScrollViewer;
if (_listScrollViewer == null)
return;
Binding binding = new Binding();
binding.Source = _listScrollViewer;
binding.Path = new PropertyPath("VerticalOffset");
binding.Mode = BindingMode.OneWay;
this.SetBinding(ListVerticalOffsetProperty, binding);
}
public double ListVerticalOffset
{
get { return (double)this.GetValue(ListVerticalOffsetProperty); }
set { this.SetValue(ListVerticalOffsetProperty, value); }
}
private static void OnListVerticalOffsetChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
BaseExtendedListUserControl control = obj as BaseExtendedListUserControl;
control.OnListVerticalOffsetChanged();
}
private void OnListVerticalOffsetChanged()
{
OnListVerticalOffsetChanged(_listScrollViewer);
}
protected virtual void OnListVerticalOffsetChanged(ScrollViewer s)
{
// do nothing
}
}
this then meant that in the user control itself I could just use:
protected override void OnListVerticalOffsetChanged(ScrollViewer viewer)
{
// Trigger when at the end of the viewport
if (viewer.VerticalOffset >= viewer.ScrollableHeight)
{
if (MoreClick != null)
{
MoreClick(this, new RoutedEventArgs());
}
}
}
private void ListBox1_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
{
EnsureBoundToScrollViewer();
}
The "hacky" thing here was that I had to use ListBox1_ManipulationCompleted and VisualTreeHelper to find my ScrollViewer - I'm sure there are better ways...
Have a look at this detect Listbox compression state from msdn blog
Use the DeferredLoadListBox.

Tooltips for CheckedListBox items?

Is there a straighforward way to set additional text to appear in a tooltip when a user's mouse is held over an item in a CheckedListBox?
What I would expect to be able to do in code is:
uiChkLstTables.DisplayOnHoverMember = "DisplayOnHoverProperty"; //Property contains extended details
Can anyone point me in the right direction to do this? I've already found a couple of articles that involve detecting which item the mouse is currently over and creating a new tooltip instance, but this sounds a little too contrived to be the best way.
Thanks in advance.
Add a Tooltip object to your form and then add an event handler for the CheckedListBox.MouseHover that calls a method ShowToolTip();
Add MouseMove event of your CheckedListBox which has the following code:
//Make ttIndex a global integer variable to store index of item currently showing tooltip.
//Check if current location is different from item having tooltip, if so call method
if (ttIndex != checkedListBox1.IndexFromPoint(e.Location))
ShowToolTip();
Then create the ShowToolTip method:
private void ShowToolTip()
{
ttIndex = checkedListBox1.IndexFromPoint(checkedListBox1.PointToClient(MousePosition));
if (ttIndex > -1)
{
Point p = PointToClient(MousePosition);
toolTip1.ToolTipTitle = "Tooltip Title";
toolTip1.SetToolTip(checkedListBox1, checkedListBox1.Items[ttIndex].ToString());
}
}
Alternately, you could use a ListView with checkboxes instead. This control has
builtin support for tooltips.
Contrived or not; that's what there is...
I'm not aware of an easier way than you have already described (although I'd probably re-use a tooltip instance, rather than creating new all the time). If you have articles that show this, then use them - or use a 3rd party control that supports this natively (none leap to mind).
I would like to expand upon Fermin's answer in order to perhaps make his wonderful solution slightly more clear.
In the form that you're working in (likely in the .Designer.cs file), you need to add a MouseMove event handler to your CheckedListBox (Fermin originally suggested a MouseHover event handler, but this did not work for me).
this.checkedListBox.MouseMove += new System.Windows.Forms.MouseEventHandler(this.showCheckBoxToolTip);
Next, add two class attributes to your form, a ToolTip object and an integer to keep track of the last checkbox whose tool tip was shown
private ToolTip toolTip1;
private int toolTipIndex;
Finally, you need to implement the showCheckBoxToolTip() method. This method is very similar to Fermin's answer, except that I combined the event callback method with the ShowToolTip() method. Also, notice that one of the method parameters is a MouseEventArgs. This is because the MouseMove attribute requires a MouseEventHandler, which then supplies MouseEventArgs.
private void showCheckBoxToolTip(object sender, MouseEventArgs e)
{
if (toolTipIndex != this.checkedListBox.IndexFromPoint(e.Location))
{
toolTipIndex = checkedListBox.IndexFromPoint(checkedListBox.PointToClient(MousePosition));
if (toolTipIndex > -1)
{
toolTip1.SetToolTip(checkedListBox, checkedListBox.Items[toolTipIndex].ToString());
}
}
}
Run through your ListItems in your checkbox list of items and set the appropriate text as the item 'title' attribute, and it will display on hover...
foreach (ListItem item in checkBoxList.Items)
{
//Find your item here...maybe a switch statement or
//a bunch of if()'s
if(item.Value.ToString() == "item 1")
{
item.Attributes["title"] = "This tooltip will display when I hover over item 1 now, thats it!!!";
}
if(item.Value.ToString() == "item 2")
{
item.Attributes["title"] = "This tooltip will display when I hover over item 2 now, thats it!!!";
}
}

Categories