Unable to get LIstBoxItem from ListBox - c#

I am unable to get ListBoxItem from ListBox. I have created ListBox dynamically; it is not in XAML. I just set ItemsSource and I have values in all the items but cannot access/convert each item as ListBoxItem.
for (int i = 0; i < listBox.Items.Count; i++)
{
ListBoxItem item = (ListBoxItem)listBox.ItemContainerGenerator.ContainerFromItem(listBox.Items[i]);
// item is null after above statement
}
Note: I just checked 'listBox.ItemContainerGenerator.Status' . listBox.ItemContainerGenerator.Status is 'notStarted'.
What to do now?

It sounds like you are not giving WPF enough time to render the <ListBoxItem> objects before calling your method.
A common way of accessing the ListBoxItems right after its Items property is set is to use the ItemContainerGenerator.StatusChanged event, like this:
void MyConstructor()
{
listBox.ItemsSource = someCollection;
listBox.ItemContainerGenerator.StatusChanged +=
ItemContainerGenerator_StatusChanged;
}
void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
{
// If containers have been generated
if (listBox.ItemContainerGenerator.Status ==
System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated)
{
// Remove event
listBox.ItemContainerGenerator.StatusChanged -=
ItemContainerGenerator_StatusChanged;
// Do whatever here
foreach(var item in listBox.Items)
{
var item = (ListBoxItem)listBox.ItemContainerGenerator.ContainerFromItem(item);
// do whatever you want with the item
}
}
}
WPF runs code at different DispatcherPriorities. Code run in the constructor or on load is run at Normal priority, while the generation of ListBoxItem objects doesn't occur until Render priority, which runs after all Normal priority items have finished running.
You could alternatively use the Dispatcher to run your code at a later dispatcher priority than Render as well.

Why are you casting the listbox to a listboxitem?
Here is a simular question about getting the selected items
listbox selected items in winform
You should be able to get the item by it's index
ListBox1.Items.Item(index)

Related

Is there a way to assign InputGestureText for the first 10 items of a MenuItem ItemSource?

I'm trying to either create a template that will assign static values for the InputGestureText of up to the first 10 items of a MenuItem's ItemSource or do it from the code-behind after an event fires but I'm having no luck trying to get the actual MenuItem object.
I've been testing out different events being fired from the MenuItem but everytime I try to loop through the MenuItem's Items property, I'm getting string objects instead of the MenuItem object which I want in-order to assign a value to its InputGestureText.
Here's the XAML for the context menu:
<MenuItem x:Name="ClassNameContext_1"
Header="Suggested Names"
ItemsSource="{Binding Path=DataContext.ClassNameList, Source={x:Reference ImgView}}"
Click="ClassNameContext_Click"
MouseEnter="ClassNameContext_MouseEnter"
SubmenuOpened="ClassNameContext_1_SubmenuOpened"/>
Source Code for my attempts:
private void ClassNameContext_1_SubmenuOpened(object sender, RoutedEventArgs e)
{
MenuItem suggestedNames = e.OriginalSource as MenuItem;
if (suggestedNames == null)
return;
suggestedNames.InputGestureText = "TEST";
int index = 0;
foreach (var item in suggestedNames.ItemContainerGenerator.Items)
{
MenuItem blah = item as MenuItem;
var bloo = item.GetType();
var bruh = suggestedNames.ItemContainerGenerator.ContainerFromIndex(index);
}
}
Basically up to the first 10 items will be assigned InputGestureTexts starting from F1 to F10.
EDIT
The reason why this is not a duplicate of the specified post is because the user there was working with statically created MenuItems whereas here it is being loaded from an ItemSource which can dynamically change given events that add or remove from the collection.

Which Item is user focused in listview xamarin forms

I am a student learning xamarin forms, I am trying to create a basic chat app in this I want to know how to get position of current item in listview that's user watching. When a new message received i want to know if user is at bottom or not if at bottom focus the new and if not at the bottom then just add not by adding focus to it.
you get the selected item from the Xamarin.Forms.ListView.SelectedItem property of your ListView.
If your ListView.ItemSource is of a type that allows using IndexOf you can now do something like
int position = (yourlistview.ItemSource as ObservableCollection<your type>).IndexOf(yourlistview.SelectedItem)
Update:
ok I think i understood what you want.
In most cases more than one item is currently shown when using a listview. So their exists not a single index
but i think you just want to know if the last item of the list is visible/the user has scrolled to the end?
If so ListView has an ItemAppearing event. I use it for example to load more data from an websource if the user scrolled through the first 100 items.
You could do something like this
listview.ItemAppearing += listviewItemAppearing;
listview.ItemDisappearing += listviewItemDisappearing;
bool m_scrolledToEnd;
private void listviewItemDisappearing(object sender, ItemVisibilityEventArgs e)
{
if(e.Item == yourlastiem)
m_scrolledToEnd = false;
}
private void listviewItemAppearing(object sender, ItemVisibilityEventArgs e)
{
if(e.Item == yourlastiem)
m_scrolledToEnd = true;
}
if you realy need to know if a specific index is shown you could create a List<int> m_idxlist;
and in the appearing event add the index of the item to the list
and in the disappearing event remove the index of the item from the list.
Then you will have a list where all indexes of the items currently shown are stored.
From the Documentation
ListView supports selection of one item at a time. Selection is on by
default. When a user taps an item, two events are fired: ItemTapped
and ItemSelected. Note that tapping the same item twice will not fire
multiple ItemSelected events, but will fire multiple ItemTapped
events. Also note that ItemSelected will be called if an item is
deselected.
To detect selecting an item, you can add a method, onSelection:
void OnSelection (object sender, SelectedItemChangedEventArgs e)
{
if (e.SelectedItem == null) {
return; //ItemSelected is called on deselection, which results in SelectedItem being set to null
}
DisplayAlert ("Item Selected", e.SelectedItem.ToString (), "Ok");
//((ListView)sender).SelectedItem = null; //uncomment line if you want to disable the visual selection state.
}
To disable selection just set the selectedItem to null:
SelectionDemoList.ItemSelected += (sender, e) => {
((ListView)sender).SelectedItem = null;
};

Windows 10 uwp listview selection changed not working

Windows 10 uwp app with a listview to just list out strings. First of all, I have an observable collection of strings in my xaml code behind. Because I still dont understand proper data binding in xaml, I am currently adding the strings to tje listview by doing a foreach loop on the observable collection and then doing
Listview1.Items.Add (new TextBlock {Text = myString});
However, is binding in this case as easy as setting my listview ItemsSource to my observablecollection?
My main issue though is I want to know when a user selects a string in the listview and what string they selected. So, I wired up to the listview SelectionChanged event. This event will raise when I select an item in the list, however
var selectedString = e.AddedItems.First().ToString();
Does not give me the selected string value. Also, there seems to be a possible recursion issue with this event. At one point, my breakpoint hit twice even though I had only selected an item in the listview one time.
So, main question is how to i get the selected string from the listview but also would appreciate suggestions or comments on data binding and if there could be recursion with this event.
EDIT: After trying the last two answers, I am still having some issues here. I cannot get the string that is selected. Using both answers below, I get the same results. First, there is some recursion because clearly the event does fire twice most times even when the list is selected only one time. Also, in both cases, the string is never populated with the selection. In fact, the breakpoint will hit at the line but then skip to the end of the event handler method and I cannot inspect any of the variables or arguments. I even wrapped it up in a try catch block but it never runs the rest of the code in the try block and never catches an exception. All it does is skip to the end of the event handler method but then take me to a file called SharedStubs.g.cs and in there, it hits at the end of this method
// Signature, Windows.UI.Xaml.UnhandledExceptionEventHandler.Invoke, [rev] [return] [Mcg.CodeGen.ComHRESULTReturnMarshaller] void__int, [rev] [in] [Mcg.CodeGen.WinRTInspectableMarshaller] object____mcg_IInspectable, [rev] [in] [GenericTypeMarshaller] -> T,
[global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
[global::System.Runtime.InteropServices.McgGeneratedMarshallingCode]
internal static int Proc_object__TArg0__<TArg0>(
object __this,
global::System.Runtime.InteropServices.__vtable_IInspectable* unsafe_sender,
void* unsafe_e,
global::System.IntPtr __methodPtr)
{
// Setup
object sender = default(object);
TArg0 TArg0__arg = default(TArg0);
try
{
// Marshalling
sender = global::System.Runtime.InteropServices.McgMarshal.IInspectableToObject(((global::System.IntPtr)unsafe_sender));
TArg0__arg = (TArg0)global::System.Runtime.InteropServices.McgModuleManager.ComInterfaceToObject(
((global::System.IntPtr)unsafe_e),
typeof(TArg0).TypeHandle
);
// Call to managed method
global::McgInterop.Intrinsics.HasThisCall__Proc_object__TArg0__<TArg0>(
__this,
__methodPtr,
sender,
TArg0__arg
);
global::System.Runtime.InteropServices.DebugAnnotations.PreviousCallContainsUserCode();
// Return
return global::McgInterop.Helpers.S_OK;
}
catch (global::System.Exception hrExcep)
{
// ExceptionReturn
return global::System.Runtime.InteropServices.McgMarshal.GetHRForExceptionWinRT(hrExcep);
}
}
And the sender in this method is ListView. After it hits in this method, the debugger just sort of hangs. I never get a real exception or error and it never really stops. I can hit continue but it just sits idle. So, the above is the only clue I really have. Not sure why this would hit but not the try/catch block and why I would never get any further exception, stack trace, etc...
Thanks!
Can you please try this one?
private void Listview1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
TextBlock textBlock = (sender as ListView).SelectedItem as TextBlock;
string value = textBlock.Text;
// OR
string value2 = (e.AddedItems[0] as TextBlock).Text;
// OR
string value3 = (e.AddedItems.First() as TextBlock).Text;
}
First of all, binding string items to a listview requires one line of code. You don't have to create a XAML template for that since you're not binding a object with properties. You can just do this:
Listview1.ItemsSource = YourObservableCollection();
It will bind your collection to your ListView.
As for the selection event, instead of SelectionChanged, you can use ItemClick event. The event args will give you the selected item aka the string by calling e.ClickedItem.
First, enable your ListView1's IsItemClickEnabled. Set it from false to true. Then add the ItemClick event.
private void ListView1_ItemClick(object sender, ItemClickEventArgs e)
{
e.ClickedItem;
}
This will return the value selected, in your case, the string.
Hope it helps!
You get the currently selected item in a ListView using the SelectedItem property and since you are adding TextBlock elements to the Items collection you should cast the SelectedItem property to a TextBlock and then access its Text property to get the string value:
private void Listview1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
TextBlock textBlock = Listview1.SelectedItem as TextBlock;
if (textBlock != null)
{
string s = textBlock.Text;
}
}
you can also use SelectionChanged event to get the value selected by user.
Here is how the code will look like :
In XAML :
ListView Name="sourceList"
ItemsSource="{Binding itemsource}"
SelectionChanged="sourceList_SelectionChanged"
In Code behind :
private void sourceList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
string selectedSource = Convert.ToString(((ListView)sender).SelectedItem);
}

C# Selecting same index on multiple listBox

Okay, so I have four listBox controls. I want to select the same index on all four listBox when one item is clicked on any of them. To be mentioned, I do change the index sometimes in the program. I tryed using a method listSelectChange (int index) and adding for each listBox an event for selectIndexChange, but it would activate the event even if the select is made by the program and not by user-control.
Please don't use classes, just a brute method would be fine!
You can unsubscribe from selectedIndexChanged before you update the ListBox and re-subscribe to it immediately after that. It's a common practice.
Since you gave no code example I'm doing some guessing here.
// Enumerable of all the synchronized list boxes
IEnumerable<ListBox> mListBoxes = ...
...
public void OnSelectedIndexChanged(object sender, EventArgs e) {
var currentListBox = (ListBox)sender;
// Do this for every listbox that isn't the one that was just updated
foreach(var listBox in mListBoxes.Where(lb => lb != currentListBox)) {
listBox.SelectedIndexChanged -= OnSelectedIndexChanged;
listBox.SelectedIndex = currentListBox.SelectedIndex;
listBox.SelectedIndexChanged += OnSelectedIndexChanged;
}
}

Listbox items at the bottom were not automatically selected

I have this subtle program regarding the behavior of listbox. My listbox is binded with an observable list in the viewmodel. There are 2 ways in addding an item in the listbox. First is ADD a single item then that item would be selected directly. This works fine.
The second way was LOAD which by its name will be adding more than 1 item in the lisbox. Now the problem is when loading items more than the listbox can accomodate in the view, those items that are not in view (items at the bottom thus need to be scrolled in order for it to be viewed) was not automatically selected...
Only the items that are by default viewed are the ones selected:
private void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
{
if (listBoxAddresses.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated) return;
for (int i = 0; i < TestSetting.DeviceSettings.Count; i++)
{
ListBoxItem myListBoxItem = (ListBoxItem)(listBoxAddresses.ItemContainerGenerator.ContainerFromItem(TestSetting.DeviceSettings[i]));
if (myListBoxItem != null)
{
myListBoxItem.IsSelected = true;
}
}
listBoxAddresses.ItemContainerGenerator.StatusChanged -= ItemContainerGenerator_StatusChanged;
}
I wonder if this is just a natural behavior for listbox.
I just realize this now...setting my listbox to :
VirtualizingStackPanel.IsVirtualizing="False"
did all the trick. Thanks to Dr.WPF for the idea. Though there are consequences for turning off virtualization (performance) but it won't matter that much.

Categories