Contextual action bar set a button to invisible - c#

I have implemented a custom contextual action bar with two buttons : one for deleting selected items from a listview and the other one for editing selected item . What I am trying to do is to make the editButton invisible when two or more items have been selected. I tried doing it this way but nothing happens:
public void OnItemCheckedStateChanged (ActionMode mode, int position, long id, bool check)
{
SetSubtitle (mode);
if (listview.CheckedItemCount > 1) {
disableButtonFlag = true;
} else
disableButtonFlag = false;
self.InvalidateOptionsMenu();
}
public bool OnCreateActionMode (ActionMode mode, IMenu menu)
{
self.MenuInflater.Inflate (Resource.Menu.CAB_menu, menu);
if (disableButtonFlag) {
menu.FindItem(Resource.Id.action_edit).SetVisible(false);
} else {
menu.FindItem(Resource.Id.action_edit).SetVisible(true);
}
mode.Title = "Select Items";
SetSubtitle (mode);
return true;
}

This is how handling multiple items works for me:
private void listView_SelectedIndexChanged(object sender, EventArgs e)
{
if(listView.SelectedIndices.Count > 1)
{
MessageBox.Show("Multiple rows selected!");
}
}
If selected index changes, check for how many indices are checked. If more than 1 (=multiple), fire your code.

Finally I found my mistake! It was that instead of declaring:
if (listview.CheckedItemCount > 1) {
disableButtonFlag = true;
} else
disableButtonFlag = false;
within my OnCreateActionMode method and calling Activity.InvalidateOptionsMenu() in my OnItemCheckedStateChanged()method I should have declared these rows within my OnPrepareActionMode() method and then called ActionMode.Invalidate() within the OnItemCheckedStateChanged()method.

Related

Get the index of Item selected in ListView

I've been searching for about an hour already and couldn't find a best solution.
I am migrating from VB.NET to C# Forms and to C# WPF.
Never mind that...
so I use this code for C# forms and it works, but not in C# WPF
if (ListView1.SelectedItems.Count > 0)
{
for (lcount = 0; lcount <= ListView1.Items.Count - 1; lcount++)
{
if (ListView1.Items[lcount].Selected == true)
{
var2 = lcount;
break;
}
}
}
this is the way I want to get the index of the item clicked in listbox.
I have the error in .SELECTED
please help.
You can get SelectedIndex from listView. No need to traverse over all items because as per your code you seems to be interested in index of any selected item.
var2 = ListView1.SelectedIndex;
OR
simply this will work if interested in only first index:
if (lst.SelectedItems.Count > 0)
{
var2 = lst.Items.IndexOf(lst.SelectedItems[0]);
}
If you are using the .NET Compact Framework, SelectedIndex is not supported. For a general solution, I prefer SelectedIndices:
ListView.SelectedIndexCollection indices = lst.SelectedIndices;
if (indices.Count > 0)
{
// Do something with indices[0]
}
For Visual Studio 2015, SelectedIndex does not seem to be available. Instead, you can use SelectedIndices[x] where x=0 will give you the first selected item:
listView.SelectedIndices[0]
You can also set the MultipleSelect property to false to only allow one item to be selected at a time.
It can return NULL. Also the SelectedIndexChanged event can be FIRED TWICE. And the first time, there nothing selected yet.
So the only safe way to find it is like this:
private void lv1_SelectedIndexChanged(object sender, EventArgs e)
{
if (lv1.FocusedItem == null) return;
int p = lv1.FocusedItem.Index;
... now int p has the correct value...
sColl.Clear();
string item = String.Empty;
if (listView1.SelectedItems.Count > 0) {
for (int i = 0; i < listView1.SelectedItems.Count; i++) {
if (listView1.SelectedItems[i].Selected) {
int i2 = listView1.SelectedItems[i].Index;
item = listView1.Items[i2].Text;
sColl.Add(item);
}
}
}
listView1.SelectedItems.Clear();
foreach (var itemS in sColl)
{
string items = itemS;
}
sColl.Clear();
listView1.SelectedItems.Clear();
Why don't bring back the SelectedIndex ? Add this extension after your current namespace.
public static class Extension
{
public static int SelectedIndex(this ListView listView)
{
if (listView.SelectedIndices.Count > 0)
return listView.SelectedIndices[0];
else
return 0;
}
}
Encapsulate this class in a namespace called Extensions and then add this inside your projects namespace to use the extension.
using Extensions;
Then simply use like this
private void ListView1_SelectedIndexChanged(object sender, EventArgs e)
{
int selectionindex = ListView1.SelectedIndex();
ListViewItem seletedItem = ListView1.Items[selectionindex];
}
P.S.
The extension method should have returned -1 on Else, but as long as you're using it from the SelectedIndexChanged event, you're fine as it won't get fired if there are no items.
This is by design, as the SelectedIndexChanged event gets fired twice. Once to deselect the initial item, then to select the new one.
Proper way is to return -1 and check for negative numer.
This is also why someone here got and ArgumentOutOfRange Exception.

Cannot find instance of dynamically added UserControl .Net

I have a UserControl which I am loading into a div which is inside an UpdatePanel. Here is my code for loading it:
controls.IDLControl IdlControl = LoadControl(#"~/controls/IDLControl.ascx") as controls.IDLControl;
IdlControl.ClientIDMode = ClientIDMode.Static;
IdlControl.ID = "IDLControl";
spGroup.Controls.Clear();
spGroup.Controls.Add(IdlControl);
And here is my code for trying to retrieve an instance of it:
controls.IDLControl IdlControl = RecursiveFindControl(this, "IDLControl") as controls.IDLControl;
private Control RecursiveFindControl(Control targetControl, string findControlId) {
if (targetControl.HasControls()) {
foreach (Control childControl in targetControl.Controls) {
if (childControl.ID == findControlId) {
return childControl;
}
RecursiveFindControl(childControl, findControlId);
}
}
return null;
}
But, all I get is null. I need help on figuring this out.
AFAIK, I need to re-add the control to the page on pre-init but it is one of the controls that can be added depending on which option is selected from a drop down list (which also is filled dynamically). I am stuck trying to figure out how to make this work.
You can try something like this to add your control back in the Page_Init based on the option selected in your DropDownList.
protected void Page_Init(Object sender, EventArgs e)
{
if (IsPostBack)
{
if (drpYourDropDown.Items.Count > 0 && drpYourDropDown.SelectedItem.Text == "yourOption")
{
AddIDLControl();
}
}
}
private void AddIDLControl()
{
controls.IDLControl IdlControl = LoadControl(#"~/controls/IDLControl.ascx") as controls.IDLControl;
IdlControl.ClientIDMode = ClientIDMode.Static;
IdlControl.ID = "IDLControl";
spGroup.Controls.Clear();
spGroup.Controls.Add(IdlControl);
}

Dynamically added objects and work with them

my code dynamically adding ListBoxes, which contains buttons. Buttons dynamically addind another buttons. Well... thats expectation. My code doesn't works.
Here is my code:
public Button createElements(string nameOfElement)
{
if (nameOfElement.Contains("Floor"))
{
// code creating Button
return floorButton;
}
else if (nameOfElement.Contains("Sound"))
{
// code creating Button
return soundButton;
}
else if (nameOfElement.Contains("Add"))
{
// code creating Button
return addButton;
}
return null;
}
private ListBox addNewListBox(ListBox targetElement, int ex)
{
// vytvori ListBox do hlavniho ListBoxu
ListBox elementListBox = new ListBox();
elementListBox.Name = "elementListBox" + indexY;
elementListBox.VerticalAlignment = VerticalAlignment.Top;
elementListBox.ItemsPanel = (ItemsPanelTemplate)XamlReader.Parse("<ItemsPanelTemplate xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"><StackPanel Orientation=\"Horizontal\"/></ItemsPanelTemplate>");
if (ex == 1)
{
targetElement.Items.Remove(addFloor);
targetElement.Items.Add(elementListBox);
elementListBox.Items.Add(createElements("Floor"));
elementListBox.Items.Add(createElements("Sound"));
elementListBox.Items.Add(createElements("Add"));
targetElement.Items.Add(addFloor);
indexY++;
indexX = 0;
}
return elementListBox;
}
Here is detail of final function.
private void putElements(ListBox targetElement, Button targetObject)
{
targetElement.Items.Add(targetObject);
// there's problem
MessageBox.Show("targetElement: ", targetElement.Name);
MessageBox.Show("targetObject", targetObject.Name);
}
Click event calling this function:
putElements(addNewListBox(mainListBox, 0), createElements("Sound"));
MessageBoxes prints names of objects in last function. Objects are right, but this line:
targetElement.Items.Add(targetObject);
there is problem - this line doing nothing..
Thanks for help!!
You're just adding the new ListBox to your mainListBox if the ex-value is 1, but in your case it's 0.
So your new ListBox (targetElement in putElements-method) will never be added to your mainListBox and hence not displayed. Thats why targetElement.Items.Add(targetObject); seems to not work.

Enabling button if there is at least one checked item in ListCheckBox

I am trying to do a Form where the user has to click at least one option of the ones given on the ListCheckBox in order to enable a sort of "Next" button.
However, its not working as expected since, sometimes, the button is enabled while there is no option chosen.
This is the code of the class where I do the validations:
class CampoCheckedListBox : AbstractCampo
{
private CheckedListBox checkedListBox { get; set; }
private string nombre { get; set; }
private bool obligatorio { get; set; }
public CampoCheckedListBox(string nom, CheckedListBox controller, bool oblig)
{
this.checkedListBox = controller;
this.nombre = nom;
this.obligatorio = oblig;
}
public override void validar()
{
string mensaje = "";
if (this.obligatorio && checkedListBox.CheckedItems.Count==0)
{
mensaje += "-Seleccione al menos una de las opciones de " + this.nombre + "." + Environment.NewLine;
throw new ValidationException(mensaje);
}
}
}
In my form:
private void validarCampos()
{
List<AbstractCampo> campos = new List<AbstractCampo>();
campos.Add(new Campo("Nombre", tBoxRol.Text, true, Controller.TipoValidacion.Alfanumerico));
campos.Add(new CampoCheckedListBox("Funcionalidades", chkBoxFuncionalidades, true));
try
{
Controller.validarCampos(campos);
darAlta_button.Enabled = true;
errorBox.Text = "";
}
catch (ValidationException vEx)
{
errorBox.Text = vEx.mensaje;
darAlta_button.Enabled = false;
}
}
Controller.validarCampos() just takes each object from a list and send message validar();
And I call this validarCampos() in the SelectedIndexChanged event on the ListCheckBox.
There are sometimes that I check an option and the button isnt enabled. But if I uncheck the same option and then check it again the button gets enabled.
I am pretty lost here...
Use the ItemCheck event instead of the SelectedIndexChanged event. The CheckedListBox uses CheckedItems and CheckedIndices in addition to the inherited SelectedItems and SelectedIndices so there is probably a disconnect between the 2 types and the events that are fired.
Controller.validarCampos() is to validate more then one AbstractCampo objects. Exception will be thrown and button will be disabled if there are no checked items in the first AbstractCompo object which I believe is not what you want.
The logic is a bit wrong here, you should use bool return value for Validar() and Controller.validarCampos() should throw exception if Validar() return false for all items in campos.
A couple of thoughts:
Like Mufaka said, you should probably be doing this inside a handler for the ItemCheck event instead of SelectedIndexChanged. (It might be possible to check/uncheck a box without selecting the item, but I'm not sure).
You have used the following in one of your conditions:
checkedListBox.CheckedItems.Count==0
In reading the documentation, here, and here, there are actually three states a box can be in:
Checked
Unchecked
Indeterminate
But the CheckedItems property will return the collection of items that are Checked or Indeterminate, so if your checkboxes start in the indeterminate/default state this might not be the count that you want.
edit: You can check as follows:
bool isAnyChecked = false;
foreach( var index in checkedListBox1.CheckedIndices )
{
if( checkedListBox1.GetItemCheckState( index ) == CheckState.Checked )
{
isAnyChecked = true;
break;
}
}

Is there an EventHandler in which I can check if ListBox doesn't contain any items?

I'm trying to avoid having the same code in multiple places. Which event handler would let me to check if I have any items in my ListBox on the fly?
This is how I check if I have any items in ListBox:
if (lbMessage.Items.Count > 0)
{
btnStart.Enabled = true;
}
else
{
btnStart.Enabled = false;
}
There is no event for such an occurrence (for a list of available events, check out the MSDN Documentation for this control). To make your code more re-usable, you could use a property, such as:
public bool ListBoxHasItems
{
get { return lbMessage.Items.Count > 0; }
}
Then you can just call that property each time you want to check if there are any items.

Categories

Resources