How to compare WPF ListBox Items with a String? - c#

I've seen some examples with sorting and filtering using colllectionView but none doing in a comparative logical way.
example:
// Button event to send an item from LB1 to LB2
private void BaddProduct_Click(object sender, RoutedEventArgs e)
{
if(Lb2.Items.Contains("item"))
{
MessageBox.Show("This item is already there!");
}
//second example
if(Lb2.Items.StartWith("item"))
{
MessageBox.Show("This item is already there!");
}
}
The code works for winforms. Is there an approach for WPF?
Thank you!

This code would work in the .xaml.cs file as well, as the 'code behind' has direct reference to all named, non-template WPF items.
If you would like the data sources to be a little more dynamic, I suggest using IEnumerable collections to bind your ItemSource to, and then you can perform all filtering using LINQ.
(edit: fixed typo 'datasources' to 'data sources')

For anyone that needs this approach:
//called by the collectionView
private bool UserFilter(object item)
{
string produtoItem;
//my LB1. With dynamic type i am gettting the item selected.
dynamic selectProdutoItem = LbProdutoPlano.SelectedItem;
produtoItem = selectProdutoItem.produtoPlanoNome;
if (String.IsNullOrEmpty(produtoItem))
{
return true;
}
else
{
//this will do a comparative logic on my selected item on LB 1. fichaProduto is my class and fichaProdutoProdutoNome a string of that class that is the same string or the item in LB1, produtoItem.
return ((item as fichaProduto).fichaProdutoProdutoNome.IndexOf(produtoItem, StringComparison.OrdinalIgnoreCase) >= 0);
}
}
// a button to add an item from LB1 to LB2.
private ButtonAdd_Click()
{
//created the collectionView in here having the itemSource the LB2 that is already binded.
CollectionView viewFiltro = (CollectionView)CollectionViewSource.GetDefaultView(LbProdutoPlanoEscolhido.ItemsSource);
// this is the key of this logic. The View will do a comparative logic from the retur of the UserFilter method.
viewFiltro.Filter = UserFilter;
// so if the View found it, it will count 1.
if (viewFiltro.Count == 1)
{
MessageBox.Show("This product is already in the LB2.");
}
else
{
// add the item into LB 2.
}
}
In this way, we donĀ“t have to compare observableĀ“s Collection for none of the ListBoxes. Just use the predicate Filter of the CView and check the result of it using the property COUNT. If it is 1, that means the filter seach for an item in LB1 and found it on the LB 2.

Related

C# MVVM - how doI prevent duplicated content in a multiple combobox selection?

I have five ComboBoxs which are using the same enum content.
Each ComboBox should not have the same value.
If box one has selected content "beef", box two has selected the content "beer".
And now I select "beer" in box one, and both contents should switch. I'm actually using a method with checks both with if and else (working, but really boring).
Is there a smarter solution?
For each box I have one of this trigger and Model.BoxOneValue, Model.BoxTwoValue...
private void OnBoxOneChange(PropertyChangedEventArgs e)
{
}
Can't post a full answer without that xaml but if you can pass it a ComboBox via CommandParameter
public RelayCommand<object> BoxChangeCommand { get { return new RelayCommand<object>(OnBoxChange); } }
private void OnBoxChange(Object comboBox)
{
ComboBox list = comboBox as ComboBox;
if (list != null) {
//do stuff
var items = list.Items;
var selectedItem = list.SelectedItem;
}
}
you'll need using System.Windows.Controls for the ComboBox
There is another way too, by binding your SelectedItem in the xaml to your VM and you can press a button on the frontend and the VM with figure everything out.

How to change comboBox Item Source when this comboBoxSelectionChanged property is called WPF C#

So I am using external API which is providing class called CatInfoType which have for example int number catid and string catname.
I have a combobox with properties
< ComboBox x:Name="listOfCategories_comboBox" ... SelectionChanged="listOfCategories_comboBox_SelectionChanged" DisplayMemberPath="catname" />
Then in MainWindow cs file I have:
1) list of this class
List<CatInfoType> displayedCategories_List = new List<CatInfoType>();
2) in constructor
var comboBox = listOfCategories_comboBox as ComboBox;
comboBox.ItemsSource = displayedCategories_List;
3) after some button is clicked then I am filling values of combobox:
foreach (var item in allCategories_list)
{
if (item.catparent == 0)
{
displayedCategories_List.Add(item);
}
}
Until now everything is fine, but I would like to change combobox items after same comboBoxSelectionChanged is called:
private void listOfCategories_comboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
CatInfoType selectedCategory = listOfCategories_comboBox.SelectedItem as CatInfoType;
int selectedCategoryId = selectedCategory.catid;
int selectedCategoryParentId = selectedCategory.catparent;
displayedCategories_List.Clear();
foreach (var item in allCategories_list)
{
if (item.catparent == selectedCategoryId)
displayedCategories_List.Add(item);
}
var comboBox = listOfCategories_comboBox as ComboBox; // I think those two lines are useless
comboBox.ItemsSource = displayedCategories_List;
}
However the combobox items are not getting changed. I was trying to do it in few ways. None of them get the result.
How I may do this ? Change comboBox Items "on live". After one of those item is pressed I want to clear the list and add new items to be displayed.
I hope code above and description is showing what I would like to do. In case you have questions feel free to ask.
try use ObservableCollection<CatInfoType> instead List<CatInfoType>

How to get id of the selected item in combobox and populate another combobox with it?

I have 2 comboboxes created with Ajax Toolkit. One of them has a list of systems. I wanted to fill the other combobox with a list of subsystems whenever a system is selected. I did not use DisplayMember or ValueMember and most examples are using them.
.aspx side just in case:
<ajaxToolkit:ComboBox ID="cbox1" runat="server" OnSelectedIndexChanged="cbox1_SelectedIndexChanged" />
Is this doable with what I'm trying? Is the event I used correct for the situation?(I guess not,but other events seem to be unrelated) Let me show you the code:
protected void fillSystemCombo()
{
var sysOperations = new ModelOperations.ConstantSystem.ConstantSystemOperations();
var sys = sysOperations.GetSystemList().TransactionResultList;
foreach (var item in sys)
{
cbox1.Items.Add(item.description);
}
}
This works fine and I can see the systems in my first combobox.
This is what I tried for populating the second one:
protected void cbox1_SelectedIndexChanged(object sender, EventArgs e)
{
var subSysOperations = new ModelOperations.ConstantSubSystem.ConstantSubSystemOperations();
int index = Convert.ToInt32(cbox1.SelectedItem.Value);//i think this should get the id...
var subsys = subSysOperations.GetSubSystemList().TransactionResultList;
foreach (var item in subsys)
{
if (item.sysID == index)
{
cbox2.Items.Add(item.description);
}
}
}
sysID is the foreign key in SubSystem which is the ID of System. By the way, my SelectedIndexChanged event never fired when I was debugging the program even though I clicked on an item in combobox.
I've actually found the answer after carefully reading the parameters taken by Items.Add. It wants a ListItemso if I create a ListItem inside the loop I can finally add my items with both a Text and a Value like this:
foreach (var item in sys)
{
combo1.Items.Add(new ListItem { Text = item.description, Value = item.ID.ToString() });
}
After that I can get the index with
int index = Convert.ToInt32(combo1.SelectedValue);

How can I programmatically select specified ListBox items?

I've got this code that populates a ListBox when a flyout is opened:
private void flyoutOpenPhotosets_Opened(object sender, object e)
{
lstbxPhotosets.ItemsSource = PhotraxSQLiteUtils.GetPhotosets();
foreach (String pset in App.CurrentlyMappedPhotosets)
{
int lstbxIndex = lstbxPhotosets.Items.IndexOf(pset);
if (lstbxIndex >= 0)
{
lstbxPhotosets.Items[lstbxIndex].? what now?
}
}
}
GetPhotosets returns a List. That part works (the list box is populated with the appropriate string values)
The problem is with the rest of the code (the foreach block).
CurrentlyMappedPhotosets is also a List. I want matching members among the strings in CurrentlyMappedPhotosets and those in the ListBox to cause the item in the ListBox to be selected when the flyout displays.
I was hoping to do be able to do something like this:
lstbxPhotosets.Items[lstbxIndex].Selected = true;
...but lstbxPhotosets is disallowing that.
So how can I programmatically select specified ListBox items?
Use
lstbxPhotosets.SelectedIndex = lstbxIndex

How to update ListView's selected item?

I have a ListView which displays multiple rows of ListViewItems. The user is able to edit one of these items through a dialog which opens after clicking 'Edit.' When the dialog closes I would like to modify the selected ListViewItem such that it reflects the new settings.
Here is how I currently update my item:
private void btnEditSnmpV3Setting_Click(object sender, EventArgs e)
{
if (lstVwSNMPv3Settings.SelectedItems.Count > 0)
{
ListViewItem selectedItem = lstVwSNMPv3Settings.SelectedItems[0];
NetworkDiscoverySnmpSetting settings = (NetworkDiscoverySnmpSetting)selectedItem.Tag;
NetworkDiscoverySnmpV3SettingsDialog dialog = new NetworkDiscoverySnmpV3SettingsDialog(settings);
//Pass in the owner for centering of dialog.
if (dialog.ShowDialog(this) == DialogResult.OK)
{
selectedItem.SubItems.Clear();
selectedItem.Text = settings.SnmpV3Username;
selectedItem.SubItems.Add(settings.SecurityMode.ToString());
selectedItem.SubItems.Add(settings.AuthenticationProtocol.ToString());
selectedItem.SubItems.Add(settings.PrivacyProtocol.ToString());
selectedItem.Tag = settings;
}
}
}
I found this to be a poor solution due to the fact that I need to touch code in multiple places if my ListView's number of columns changes.
I handled this code-reuse issue during the 'Add' event (as opposed to 'Edit') by giving NetworkDiscoverySnmpSetting a utility method:
public ListViewItem ToListViewItem()
{
ListViewItem listViewItem = new ListViewItem();
listViewItem.Text = SnmpV3Username;
listViewItem.SubItems.Add(SecurityMode.ToString());
listViewItem.SubItems.Add(AuthenticationProtocol.ToString());
listViewItem.SubItems.Add(PrivacyProtocol.ToString());
listViewItem.Tag = this;
return listViewItem;
}
which is used like so:
private void btnAddSnmpV3Setting_Click(object sender, EventArgs e)
{
NetworkDiscoverySnmpSetting settings = new NetworkDiscoverySnmpSetting(NetworkDiscovery.ID);
NetworkDiscoverySnmpV3SettingsDialog dialog = new NetworkDiscoverySnmpV3SettingsDialog(settings);
//Pass in the owner for centering of dialog.
if (dialog.ShowDialog(this) == DialogResult.OK)
lstVwSNMPv3Settings.Items.Add(settings.ToListViewItem());
}
Unfortunately, ListView.SelectedItems does not allow collection-modification. As such, this does not compile:
lstVwSNMPv3Settings.SelectedItems[0] = settings.ToListViewItem();
How should I change my first code-snippet so that I do not need to update my code in multiple places when ListView's columns change?
You can modify the element itself rather than replacing it with another one, because ListViewItem is a class, so it's a reference type.
In order to do this follow these steps:
get currently selected item and save it to variable like this: ListViewItem selectedItem = lstVwSNMPv3Settings.SelectedItems[0];
modify your ToListViewItem method to void ToListViewItem(ListViewItem listViewItem) (return void and take ListViewItem object as parameter and modify it instead of creating a new object. It should also rather modify properties of existing subitems than creating new ones. It can look more or less like this:
public void ToListViewItem(ListViewItem listViewItem)
{
listViewItem.Text = SnmpV3Username;
listViewItem.SubItems[0].Text = SecurityMode.ToString();
listViewItem.SubItems[1].Text = AuthenticationProtocol.ToString();
listViewItem.SubItems[2].Text = PrivacyProtocol.ToString();
listViewItem.Tag = this;
}
call ToListViewItem(selectedItem);
you don't have to assign the modified item back to the collection, because you use a reference, which means you've just modify the same object that's in the ListView
I did a quick test and the method seems to modify texts of existing items without issues.
ListViewItems have a bool Selected property that you can toggle to make them selected or not selected.
A much simpler solution, that worked for me:
lstVwSNMPv3Settings.Items[lstVwSNMPv3Settings.SelectedIndices[0]] = myNewItem;
But be careful to first make sure there is an item selected:
if (lstVwSNMPv3Settings.SelectedIndices.Count > 0) { ... }

Categories