TreeListView and hierarchical checkboxes - c#

I am using TreeListView with:
this.tlv.CheckBoxes = true;
this.tlv.TriStateCheckBoxes = true;
this.tlv.HierarchicalCheckboxes = true;
Hierarchical with tristate works well, except one: the user can set the CheckState.Indeterminate by clicking the mouse, and I don't need it. For this I use 2 delegate that are not working correctly. How to make that work?
this.tvl.CheckStateGetter = delegate(object rowObject)
{
if (((ModelData)rowObject).IsChecked == true)
{
return CheckState.Checked;
}
else
{
if (((ModelData)rowObject).IsChecked == false)
{
return CheckState.Unchecked;
}
else
{
return CheckState.Indeterminate;
}
}
};
this.tvl.CheckStatePutter = delegate(object rowObject, CheckState newValue)
{
if (((ModelData)rowObject).Child.Count > 0)
{
if ((((ModelData)rowObject).Child.Where(x => x.IsChecked != null).Any(x => (bool)x.IsChecked) &&
((ModelData)rowObject).Child.Where(x => x.IsChecked != null).Any(x => !(bool)x.IsChecked)) ||
(((ModelData)rowObject).Child.Any(x => x.IsChecked == null)))
{
((ModelData)rowObject).IsChecked = null;
return CheckState.Indeterminate;
}
else
{
if (((ModelData)rowObject).Child.Where(x => x.IsChecked != null).All(x => (bool)x.IsChecked))
{
((ModelData)rowObject).IsChecked = true;
return CheckState.Checked;
}
else
{
((ModelData)rowObject).IsChecked = false;
return CheckState.Unchecked;
}
}
}
else
{
((ModelData)rowObject).IsChecked = (newValue == CheckState.Checked) ? true : false;
return newValue;
}
};

According to the documentation, "CheckStateGetters" are not allowed in the treelistview.
From the webpage:
One major problem is that we don’t know the checkedness of all the
subitems. When an ObjectListView has a CheckStateGetter installed, the
only way we can know if an item is checked is by calling the
CheckStateGetter on that item. We can’t reason about what is checked
or unchecked – we always have to ask. In our disk browser example, we
would have to ask all 700,000 items if it was checked. That’s never
going to work, so with hierarchical checkboxes, we don’t allow
CheckStateGetters to be installed.
http://objectlistview.sourceforge.net/cs/blog7.html

Related

Picker gives me an ArgumentOutOfRangeException, why is this happening?

I need my picker to hide elements if authorization == true.
private async void Picker_Unfocused(object sender, FocusEventArgs e)
{
try
{
await DisplayAlert("try", picker.SelectedIndex.ToString(), "OK");
if (response.domains[picker.SelectedIndex].authorization == true)
{
userNameEntry.IsVisible = false;
passwordEntry.IsVisible = false;
userLabel.IsVisible = false;
}
else
{
userNameEntry.IsVisible = true;
passwordEntry.IsVisible = true;
userLabel.IsVisible = true;
}
}
catch(System.ArgumentOutOfRangeException)
{
await DisplayAlert("catch", picker.SelectedIndex.ToString(), "OK");
}
}
This won't help. I get an ArgumentOutOfRangeException. Does anyone know why? It is important to me that this works.
Edit: Code is now current code. displayalerts just give me 0 if I select the first item, 1 if I select the second, etc. I still don't know what's going on. If the value of SelectedIndex is 0(or whatever I select) I shouldn't get an ArgumentOutOfRangeException, right?
When the picker is not yet initialized or can view a null value and is thus empty, the SelectedIndex property will give you a value of -1. This value is not valid for use in an array.
You should enrich your code to account for this possibility, for instance like this:
if (picker.SelectedIndex > -1 && response.domains[picker.SelectedIndex].authorization == true)
{
userNameEntry.IsVisible = false;
passwordEntry.IsVisible = false;
userLabel.IsVisible = false;
}
else
{
userNameEntry.IsVisible = true;
passwordEntry.IsVisible = true;
userLabel.IsVisible = true;
}

Getting rid of unnecessary loops

In my game I'm going to have a lot of interactions in which I'll need to see if a player has an item, and if he does and something else is true, then do an action. Described in the following code.
private void SetTinderInPit()
{
MouseState currentMouseState = Mouse.GetState();
if (player.NextToFirePit == true)
{
foreach (Item item in player.PlayerInventory.Items)
{
if (item.ItemName == "tinder")
{
foreach (Item pit in allItemsOnGround)
{
if (pit.ItemName == "firepit" &&
pit.ItemRectangle.Contains(MouseWorldPosition) &&
currentMouseState.LeftButton == ButtonState.Pressed &&
oldMouseState.LeftButton == ButtonState.Released)
{
item.ItemName = "empty";
pit.ItemName = "firepitwithtinder";
pit.Texture = Content.Load<Texture2D>("firepitwithtinder");
}
}
}
}
oldMouseState = currentMouseState;
}
}
As you can see, this is ugly to look at and I think that there would be a better way to do this, but I'm not sure how. Since there will be a lot of these types of methods, I'm wondering what would be the best way to accomplish this?
Seems like you could get rid of (actually hide) the loops altogether by using some LINQ:
private void SetTinderInPit()
{
MouseState currentMouseState = Mouse.GetState();
if (player.NextToFirePit)
{
Item tinder = player.PlayerInventory.Items.FirstOrDefault(i => i.ItemName == "tinder");
if (tinder != null)
{
Item firepit = allItemsOnGround.FirstOrDefault(i => i.ItemName == "firepit" && i.ItemRectangle.Contains(MouseWorldPosition));
if (firepit != null &&
currentMouseState.LeftButton == ButtonState.Pressed &&
oldMouseState.LeftButton == ButtonState.Released)
{
tinder.ItemName = "empty";
firepit.ItemName = "firepitwithtinder";
firepit.Texture = Content.Load<Texture2D>("firepitwithtinder");
}
}
oldMouseState = currentMouseState;
}
}
This has the added advantage of short-circuiting the loop when the item is found. It also makes it easy to check against things other than the name (like an "IsFlammable" or "CanContainFire" property) so you could use multiple items instead of just "tinder" and "firepit".
If you actually intended to remove all firepits and tinder, use:
private void SetTinderInPit()
{
MouseState currentMouseState = Mouse.GetState();
if (player.NextToFirePit)
{
foreach (Item tinder in player.PlayerInventory.Items.Where(i => i.ItemName == "tinder")
{
foreach (Item firepit in allItemsOnGround.Where(i => i.ItemName == "firepit"))
{
if (firepit.ItemRectangle.Contains(MouseWorldPosition) &&
currentMouseState.LeftButton == ButtonState.Pressed &&
oldMouseState.LeftButton == ButtonState.Released)
{
tinder.ItemName = "empty";
firepit.ItemName = "firepitwithtinder";
firepit.Texture = Content.Load<Texture2D>("firepitwithtinder");
}
}
}
oldMouseState = currentMouseState;
}
}
Quick caveat; this code will remove all firepits with the first tinder, leaving the other tinders unscathed. I could unravel the loops to remove everything, but this function matches the provided one; and besides, I'm assuming thats not the intended behavior.
Note you do not need ToList anywhere because you are not modifying the collection during enumeration. You can always modify the items in the collection, proved with the following test:
class IntWrapper
{
public int value;
public IntWrapper(int value)
{
this.value = value;
}
}
class Program
{
static void Main(string[] args)
{
List<IntWrapper> test = new List<IntWrapper>() { new IntWrapper(1), new IntWrapper(2), new IntWrapper(3), new IntWrapper(4), new IntWrapper(5) };
foreach (IntWrapper i in test.Where(i => i.value == 1))
{
i.value = 0;
}
foreach (IntWrapper i in test)
{
Console.WriteLine(i.value);
}
Console.ReadLine();
}
}
The only real change I would make to your existing code would be to move the check for mouse state early on, to avoid checking this multiple times in your loops. In addition I would use Linq to shorten the conditions (by removing the 'if' statements):
MouseState currentMouseState = Mouse.GetState();
// I would get all the conditional checks out of the way up front first
if (player.NextToFirePit &&
currentMouseState.LeftButton == ButtonState.Pressed &&
oldMouseState.LeftButton == ButtonState.Released)
{
foreach (var tinderItem in player.PlayerInventory.Items
.Where(item => item.ItemName == "tinder"))
{
foreach (var firePit in allItemsOnGround
.Where(item => item.ItemName == "firepit" &&
item.ItemRectangle.Contains(MouseWorldPosition)))
{
tinderItem.ItemName = "empty";
firePit.ItemName = "firepitwithtinder";
firePit.Texture = Content.Load<Texture2D>("firepitwithtinder");
}
}
}
oldMouseState = currentMouseState;
An alternate idea, since you were looking for a way to get rid of the 'ugly' code, would be to move some of this functionality to the player object.
I would probably use LINQ more.
Note that this is written in Notepad, not visual studio so is more of a pseudo-code.
private void SetTinderInPit()
{
var currentMouseState = Mouse.GetState();
if (!player.NextToFirePit) return;
player.PlayerInventory.Items.Where(item => item.ItemName == "tinder").ToList().ForEach(item =>
{
allItemsOnGround.Where(x => x.ItemName == "firepit" &&
x.ItemRectangle.Contains(MouseWorldPosition) &&
currentMouseState.LeftButton == ButtonState.Pressed &&
oldMouseState.LeftButton == ButtonState.Released)
.ToList().ForEach(pit =>
{
item.ItemName = "empty";
pit.ItemName = "firepitwithtinder";
pit.Texture = Content.Load<Texture2D>("firepitwithtinder");
});
});
oldMouseState = currentMouseState;
}

c# menuItem1 will not disable

Is this wrong?
I always get "cb1 and firmware" even if my checkBox2 is checked. I also tried with just & instead of &&.
It was working fine before I had to add it into thread to get UI to update correctly.
private void MyWorkerThread2()
{
if (this.IsChecked(checkBox1) && (this.IsChecked(checkBox2) && (myString == "86.09.0000")))
{
MessageBox.Show("cb1 and firmware and cb2");
Prep.clean();
startedimage();
fscreate();
wipefiles();
}
else if ((this.IsChecked(checkBox1) && (myString == "86.09.0000")))
{
MessageBox.Show("cb1 and firmware");
Prep.clean();
startedimage();
wipefiles();
}
else if (myString == "86.09.0000")
{
MessageBox.Show("firmware");
if (myThread == null)
{
Prep.clean();
startedimage();
myThread = new Thread(MyWorkerThread);
myThread.IsBackground = true;
myThread.Start();
}
}
else
{
FactoryReset();
}
}
public delegate bool IsCheckedDelegate(CheckBox cb);
public bool IsChecked(CheckBox cb)
{
if (cb.InvokeRequired)
{
return (bool)cb.Invoke(new IsCheckedDelegate(IsChecked), new Object[] { cb });
}
else
{
return cb.Checked;
}
}
I always get "cb1 and firmware" even if my checkBox2 is checked.
The fact that checkBox2 is checked isn't going to change the fact that checkBox1 is also checked and so the first if statement succeeds. If checkBox1 wasn't checked, it would fall to the other sets.
It's not clear what you're trying to do here, but I would say the first two if statements need reversed.
It seems like you only want the first to be executed when checkBox2 is NOT checked.
Change:
if ((this.IsChecked(checkBox1) && (myString == "86.09.0000")))
To:
if ((this.IsChecked(checkBox1) && (!this.IsChecked(checkBox2) && (myString == "86.09.0000")))
There are four possibilities here:
none
cb1
cb2
cb1, cb2
Try reordering the code
if (this.IsChecked(checkBox1) && (this.IsChecked(checkBox2) && (myString == "86.09.0000")))
{
MessageBox.Show("cb1 and firmware and cb2");
Prep.clean();
startedimage();
fscreate();
wipefiles();
}
else if ((this.IsChecked(checkBox1) && (myString == "86.09.0000")))
{
MessageBox.Show("cb1 and firmware");
Prep.clean();
startedimage();
wipefiles();
}

C# error - "Not all code paths return a value"

This is fairly simple method. I use entity framework to get some data and then check some values in a if statement. However right now the method is marked with red.
This is my method:
private bool IsSoleInProduction(long? shoeLastID)
{
if (shoeLastID == null)
{
MessageBox.Show(Resources.ERROR_SAVE,
"Error",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
return false;
}
ISoleService soleService =
UnityDependencyResolver.Instance.GetService<ISoleService>();
List<Sole> entity =
soleService.All().Where(s => s.ShoeLastID == shoeLastID).ToList();
if (entity.Count() != 0)
{
foreach (var items in entity)
{
if (items.Status == 20)
{
return true;
}
else
{
return false;
}
}
}
else
{
return false;
}
}
What am I missing?
You need to take advantage of LINQ with Any, replace your code:
if (entity.Count() != 0)
{
foreach (var items in entity)
{
if (items.Status == 20)
{
return true;
}
else
{
return false;
}
}
}
else
{
return false;
}
with simpler code:
return entity.Any(item => item.Status == 20);
Or even better performance:
return soleService.All()
.Any(s => s.ShoeLastID == shoeLastID
&& s.Status == 20);
Edit: With you comment, below code is what you need:
List<Sole> entity = soleService.All()
.FirstOrDefault(s => s.ShoeLastID == shoeLastID);
return entity == null ? false : entity.Status == 20;
If there's no item in your entity collection, then neither of the containing if/else branches will be executed. In this case there's no return statement anymore, because the else part won't be executed, and outside your foreach you have no return statement.
The compiler does not "see" that if
entity.Count() != 0
then your loop
foreach (var items in entity)
will run at least once. Therefore it sees a possibility of running the forech zero times, and not running the else block.
Suppose first time the entity is enumerated, it yields some (finite number of) items. Then the Count will be non-zero. Then suppose next time the same entity is enumerated then it yields no items! That would cause your code to "fall through" without returning.
It is very probably that you can guarantee that the source yields the same number of items each time it is re-enumerated. But the compiler cannot.
Solution: Just skip if (entity.Count() != 0) and do foreach right away.
You haven't retrun anything from this code block
if (entity.Count() != 0)
{
foreach (var items in entity)
{
if (items.Status == 20)
{
return true;
}
else
{
return false;
}
}
// return someting
}
You might consider doing the following. This will adhere to the "single exit-point" principle (which can sometimes help improve code clarity), and ensure you have a default value in any case:
private bool IsSoleInProduction(long? shoeLastID)
{
// The main change: A default value, assuming "no":
var isSoleInProduction = false;
if (shoeLastID == null)
{
MessageBox.Show(Resources.ERROR_SAVE,
"Error",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
isSoleInProduction = false;
}
ISoleService soleService =
UnityDependencyResolver.Instance.GetService<ISoleService>();
List<Sole> entity =
soleService.All().Where(s => s.ShoeLastID == shoeLastID).ToList();
if (entity.Count() != 0)
{
foreach (var items in entity)
{
if (items.Status == 20)
{
isSoleInProduction = true;
}
else
{
isSoleInProduction = false;
}
}
}
else
{
isSoleInProduction = false;
}
return isSoleInProduction;
}
What will be your entity.Count() is not 0 and your entity doesn't have any items?
That means your if block will work but foreach part will not work. Since your if part doesn't have any return statement, that's why you get an error.
You should put return statement in your if part.
if (entity.Count() != 0)
{
foreach (var items in entity)
{
if (items.Status == 20)
{
return true;
}
else
{
return false;
}
}
//return true or false
}
If your entity collection has no elements you will not reach a return statement - you need to add a return false forexample as last statement
As the error states there can be cases in which none of your return clause is evaluated (e.g. if there are no elements in your list).
To quickly solve it you can put a default return statement, for example by moving the last return clause outside the else statement. But it really depends on the behavior you'd expect.
private bool IsSoleInProduction(long? shoeLastID)
{
if (shoeLastID == null)
{
MessageBox.Show(Resources.ERROR_SAVE, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
ISoleService soleService = UnityDependencyResolver.Instance.GetService<ISoleService>();
List<Sole> entity = soleService.All().Where(s => s.ShoeLastID == shoeLastID).ToList();
if (entity.Count() != 0)
{
foreach (var items in entity)
{
if (items.Status == 20)
{
return true;
}
else
{
return false;
}
}
}
return false;
}
The compiler can't guarantee that the first call to Count means that the foreach will loop at least once (with good reason, because you could, if you wished, create a collection where this wasn't true). You can do this instead (with no need for the outer if):
foreach (var items in entity)
{
if (items.Status == 20)
{
return true;
}
else
{
return false;
}
}
return false;

c# event fires windows form incorrectly

I'm trying to understand what's happening here. I have a CheckedListBox which contains some ticked and some un-ticked items. I'm trying to find a way of determining the delta in the selection of controls. I've tried some cumbersome like this - but only works part of the time, I'm sure there's a more elegant solution. A maybe related problem is the myCheckBox_ItemCheck event fires on form load - before I have a chance to perform an ItemCheck. Here's what I have so far:
void clbProgs_ItemCheck(object sender, ItemCheckEventArgs e)
{
// i know its awful
System.Windows.Forms.CheckedListBox cb = (System.Windows.Forms.CheckedListBox)sender;
string sCurrent = e.CurrentValue.ToString();
int sIndex = e.Index;
AbstractLink lk = (AbstractLink)cb.Items[sIndex];
List<ILink> _links = clbProgs.DataSource as List<ILink>;
foreach (AbstractLink lkCurrent in _links)
{
if (!lkCurrent.IsActive)
{
if (!_groupValues.ContainsKey(lkCurrent.Linkid))
{
_groupValues.Add(lkCurrent.Linkid, lkCurrent);
}
}
}
if (_groupValues.ContainsKey(lk.Linkid))
{
AbstractLink lkDirty = (AbstractLink)lk.Clone();
CheckState newValue = (CheckState)e.NewValue;
if (newValue == CheckState.Checked)
{
lkDirty.IsActive = true;
}
else if (newValue == CheckState.Unchecked)
{
lkDirty.IsActive = false;
}
if (_dirtyGroups.ContainsKey(lk.Linkid))
{
_dirtyGroups[lk.Linkid] = lkDirty;
}
else
{
CheckState oldValue = (CheckState)e.NewValue;
if (oldValue == CheckState.Checked)
{
lkDirty.IsActive = true;
}
else if (oldValue == CheckState.Unchecked)
{
lkDirty.IsActive = false;
}
_dirtyGroups.Add(lk.Linkid, lk);
}
}
else
{
if (!lk.IsActive)
{
_dirtyGroups.Add(lk.Linkid, lk);
}
else
{
_groupValues.Add(lk.Linkid, lk);
}
}
}
Then onclick of a save button - I check whats changed before sending to database:
private void btSave_Click(object sender, EventArgs e)
{
List<AbstractLink> originalList = new List<AbstractLink>(_groupValues.Values);
List<AbstractLink> changedList = new List<AbstractLink>(_dirtyGroups.Values);
IEnumerable<AbstractLink> dupes = originalList.ToArray<AbstractLink>().Intersect(changedList.ToArray<AbstractLink>());
foreach (ILink t in dupes)
{
MessageBox.Show("Changed");
}
if (dupes.Count() == 0)
{
MessageBox.Show("No Change");
}
}
For further info. The definition of type AbstractLink uses:
public bool Equals(ILink other)
{
if (Object.ReferenceEquals(other, null)) return false;
if (Object.ReferenceEquals(this, other)) return true;
return IsActive.Equals(other.IsActive) && Linkid.Equals(other.Linkid);
}
There's little point that I see to do this in the ItemCheck event. Just calculate the delta when you save. Cuts out a bunch of code and trouble with spurious events.

Categories

Resources