I need to retrieve components from a listbox item. Not from a Tap or selection changed events. Is there a simple way to achieve this?
If I remember correct, in Android you can just write:
layoutRoot.findViewById(R.id.name);
Is there a similar way to do this on Windows Phone?
Update: Here's what I tried so far, but does not work:
What Daniela said in option 5 seems to work when I have the ListBoxItem. So this works fine when I have for example a Tap event on the ListBoxItem:
private void ListBoxItem_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
ListBoxItem item = sender as ListBoxItem;
// I can now retrieve a component inside the ListBoxItem
TextBox textBox = item.FindName("myTextBox") as TextBox;
}
But I want to do this when not triggering any events from a ListBoxItem.
What JoonasL said looks like something I could use but I can't get it to work.
// will not compile ( Cannot implicitly convert type 'object' to... )
ListBoxItem item = x.Items[0];
// if cast the value will be null
ListBoxItem item = x.Items[0] as ListBoxItem;
// will return the object used to populate that ListBoxItem, not the actual ListBoxItem.
// item will have a ItemViewModel object.
List<ItemViewModel> list = ....
this.myListBox.ItemsSource = list;
var item = x.Items[0]
When searching on Google I found something that I could use to find a component inside a ListBoxItem but I think there should be a easier way. Here they use a VisualTreeHelper.
Edit:
add a name to your lisbox (x:Name="something")
Cast ALL items as a List or pick out an item and cast the item as the correct type. Example:
private void Button_Click(object sender, RoutedEventArgs e)
{
var list = yourListbox.Items;
var itemCastAsCorrectObjectInstance = (ItemViewModel)list.FirstOrDefault();
textblock.Text = itemCastAsCorrectObjectInstance.LineOne;
}
ItemViewModel is a class we have created, and a list of ItemViewModels are used as itemssource for the listbox.
Here is an app example I've made for you
There are several ways to do that (some of the examples are WPF, but code is quite similar, it's just to give you a general idea)
Create listbox in code and retrieve item as in the example provided my JoonasL
private void GetUserRecommendations()
{
var obj = _helper.GetList<Recommendations>(#"http://localhost:1613/Home/GetAllRecommendations");
_items.Clear();
foreach (var item in obj)
{
_items.Add(item);
}
itemListView.ItemsSource = _items;
}
Retrieve a selected item on a changed event (or other event bound to the listbox)
void ItemView_ItemClick(object sender, ItemClickEventArgs e)
{
var itemProperty = ((ListBoxItem) e.ClickedItem).SomeProperty;
}
Provide the listbox a name and access the items by refering to the name in the code
var item = itemListView.SelectedItem as SomeClass;
Access the selected item by binding to another element (XAML only)
<Border Margin="10" BorderBrush="Silver" BorderThickness="3" Padding="8">
<DockPanel>
<TextBlock>Choose a Color:</TextBlock>
<ComboBox Name="myComboBox" SelectedIndex="0">
<ComboBoxItem>Green</ComboBoxItem>
<ComboBoxItem>Blue</ComboBoxItem>
<ComboBoxItem>Red</ComboBoxItem>
</ComboBox>
<Canvas>
<Canvas.Background>
<Binding ElementName="myComboBox" Path="SelectedItem.Content"/>
</Canvas.Background>
</Canvas>
</DockPanel>
Search the layoutroot
var myTextBlock = (TextBlock)this.FindName("myTextBlock");
Or maybe something like:
private void Somepage_Loaded(object sender, RoutedEventArgs e)
{
if (SomeCondition())
{
var children = (sender as Panel).Children;
var child = (from Control child in children
where child.Name == "NameTextBox"
select child).First();
child.Focus();
}
ListBox x = new ListBox();
ListBoxItem item = x.Items[0];
Or do you want something else?
RadDataBoundListBox has an event called ItemTap (not sure about normal ListBox) but my solution went something like this:
private void FocusTextBox(object sender, ListBoxItemTapEventArgs e)
{
txtBox = e.Item.FindChildByType<TextBox>();
var item = itemListView.SelectedItem as PanoramaApp1.//Your Selected Item Type Here;
//Do Something With item Here
itemListView.SelectedItem = null;
}
Related
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.
I have a 2 ListViews with same items in both of them. What I want to do is that when a selection is made in one ListView, the same selection should be reflected in the other ListView also. The two ListViews are bound to two different ViewModels but both the ViewModels implement the same interface.
I've overridden the Equals methods in both ViewModels.
The two ListViews are on different XAML pages. The first ListView say LV1 is in Page1.xaml and LV2 is in Page2.xaml. What I want is that when I am changing the selection in LV2 the selection in LV1 should also change( one way only ). I've set x:FieldModifier="public" on LV1 and exposing through a static property of Page1 like this:
public sealed partial class Page1 : Page
{
public static Page1 page1 { get; private set; }
}
And on Page2, I have this :
private async void LV2_ItemClick(object sender, ItemClickEventArgs e)
{
var selected = e.ClickedItem as ISomeCommonInterface;
//Comparision is successful --> Contains() always returns corect value;
if (Page1.page1.LV1.Items.ToList().Contains(selected))
{
Page1.page1.LV1.SelectedItem = null; // this works
Page1.page1.LV1.SelectedItem = selected; // this doesn't work
}
}
I've found that inside the if condition, assignment to null changes the SelectedItem of LV1 to null but the next line doesn't change it to selected ( it remains null ).
add after assignment:
Page1.page1.LV1.Select();
This works for me:
private void LV1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var selected = (sender as ListView).SelectedItem as string;
int index = -1;
for (int i = 0; i < LV2.Items.Count(); i++)
{
if (LV2.Items[i] as string == selected){
index = i;
break;
}
}
// The if becomes obsolete here, it could be replaced by
// if(index >= 0)
if (LV2.Items.ToList().Contains(selected))
{
LV2.SelectedIndex = index;
}
}
There is probably an easier way of getting the index of LV1's SelectedItem in LV2, but it should be enough to get you on the right track.
You can check out the minimal testing app I created that shows that SelectedItem works too.
Method 1 - SelectionMode="Multiple" - both ListViews in sync
You should subscribe the SelectionChanged event on both ListViews - item may not get selected only by click - and there (when selection is changed) you should sync the selection.
private void SyncSelection(object sender, SelectionChangedEventArgs e)
{
ListView listViewToAdd = ReferenceEquals(sender, firstListView) ? secondListView : firstListView;
foreach (var item in e.AddedItems)
{
if (!listViewToAdd.SelectedItems.Contains(item))
{
listViewToAdd.SelectedItems.Add(item);
}
}
foreach (var item in e.RemovedItems)
{
listViewToAdd.SelectedItems.Remove(item);
}
}
Method 2 - SelectionMode="Multiple" - update one after selecting in the other
You should subscribe the SelectionChanged event only on the ListView where items could be selected.
private void SyncSelection(object sender, SelectionChangedEventArgs e)
{
foreach (var item in e.AddedItems)
{
secondListView.SelectedItems.Add(item);
}
foreach (var item in e.RemovedItems)
{
secondListView.SelectedItems.Remove(item);
}
}
Method 3 - SelectionMode="Single"
Subscribe the SelectionChanged event on both if you want to make them be in sync or only on the selectable one if you only want to update the second based on the first.
private void SyncSelection(object sender, SelectionChangedEventArgs e)
{
ListView senderListView = (ListView)sender;
ListView listViewToAdd = ReferenceEquals(sender, firstListView) ? secondListView : firstListView;
listViewToAdd.SelectedItem = senderListView.SelectedItem;
}
You may need to replace var with your interface to make it work.
In my solution I have set the default value for list like below code
<ListBox x:Name="SelectorList"
ItemsSource="{Binding ViewStatusList}"
SelectedItem="{Binding SelectedDeviceItem,Mode=TwoWay}"
IsSynchronizedWithCurrentItem="True">
create the property for SelectedDeviceItem in my view model.
private Device _selecteddeviceitem;
public Device SelectedDeviceItem
{
get
{
return _selecteddeviceitem;
}
set
{
_selecteddeviceitem = value;
OnPropertyChanged("SelectedDeviceItem");
}
}
and passed SelectedDeviceItem = StatusList[0];
in the constructor.
But still my listbox will be shown like below.
But I need the result should be like below image
What have I missed in the this list box code?
I think this could achieve it:
Set the selected ListBoxItem to be focused.
private void ListBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var listbox = sender as ListBox;
var listboxItem =
listbox?.ItemContainerGenerator.ContainerFromItem(listbox.SelectedItem) as ListBoxItem;
listboxItem?.Focus();
}
Set focus when the ListBox loaded. This is because that the ListBoxItems may be selected before they are generated.
private void ListBox_Loaded(object sender, RoutedEventArgs e)
{
var listbox = sender as ListBox;
var listboxItem =
listbox?.ItemContainerGenerator.ContainerFromItem(listbox.SelectedItem) as ListBoxItem;
listboxItem?.Focus();
}
Note that the logic of making item being selected should not be achieved in the view model, it's just kind of a UI logic.
it seems ListboxItem not focused . Please Set ListBox to focus and item to focus
listBox.Focus();
var listBoxItem = (ListBoxItem)listBox.ItemContainerGenerator.ContainerFromItem(listBox.SelectedItem);
listBoxItem.Focus();
I'm having some trouble with Drag and Drop between different ListViews. I have a GridView that contains multiple ListView all from the same ObservableCollection. Basically, I want to be able to drag items from one ListView into another Listview but within the same GridView.
Below is the ListView Which is part of the DataTemplate for the GridView. The ListView is Bound to a ObservableCollection of string. Which is a Property or the ObservableCollection the GridView is bound too.
<ListView Name="ListingView" Height="200" HorizontalAlignment="Center" Grid.Row="1" CanDragItems="True" AllowDrop="True"
DragItemsStarting="ListView_DragItemsStarting"
DragOver="ListView_DragOver"
CanReorderItems="True"
DragItemsCompleted="ListView_DragItemsCompleted"
Drop="ListView_Drop" ItemsSource="{Binding Listing}"
/>
And here is the Code Behind for the ListView
private void ListView_DragItemsStarting(object sender, DragItemsStartingEventArgs e)
{
var item = string.Join(",", e.Items.Cast<string>());
e.Data.SetText(item);
e.Data.RequestedOperation = DataPackageOperation.Move;
}
private void ListView_DragOver(object sender, DragEventArgs e)
{
if (e.DataView.Contains(StandardDataFormats.Text))
{
e.AcceptedOperation = DataPackageOperation.Move;
}
}
private async void ListView_Drop(object sender, DragEventArgs e)
{
if (e.DataView.Contains(StandardDataFormats.Text))
{
var item = await e.DataView.GetTextAsync();
var destinationListView = sender as ListView;
var listViewItemsSource = destinationListView?.ItemsSource as ObservableCollection<string>;
if (listViewItemsSource != null)
{
listViewItemsSource.Add(item);
}
}
}
private void ListView_DragItemsCompleted(ListViewBase sender, DragItemsCompletedEventArgs args)
{
var item = string.Join(",", args.Items.Cast<string>());
var destinationListView = sender as ListView;
var listViewItemsSource = destinationListView?.ItemsSource as ObservableCollection<string>;
listViewItemsSource.Remove(item);
}
}
The Problem I have is finding a way to stop a ListView from becoming completely empty if I drag all the items out of the a ListView. Once the ListView becomes empty I can't go back and drag something into it.
The Second problem is when I drag an item and then let go of it in the same ListView it was dragged from then it deletes and does no re-add the item.
I think I need to add an If statement to the DragItemCompleted method to see If the source is the same as the target before removing the item.
Edit I seem to have fixed" the second problem by removing the CanReorderItemsProperty from the listView. I'm not sure why but it seems to have fixed up that issue. But now i can't reorder the lists :(
Look into this windows sample program https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/XamlDragAndDrop/cs
I would like to be able to select a TreeViewItem in my program on right-click. Previously, (In this question) I tried to do this by calling to SetSelectedItem() method from wherever I wanted to allow a TreeViewItem to be selected. The answer from that question compiled and ran, but did not actually allow the TreeViewItem to become selected like I wanted.
This question that I've been looking at is pretty much the exact same question as this one, with the exception of the hierachicalDataTemplate. My TreeView does not have a hierachicalDataTemplate, and if it is unnecessary for my program I would like to avoid it.
This is what I have compiling, but not affecting change right now...
//Sets selected item in TreeView and passes to MainWindowViewModel
private void SetSelectedItem()
{
MainWindowViewModel.SelectedItem = Tree_One.SelectedItem as TreeViewItem;
}
//**** This is the function this question is about -- It's Supposed to select item on RightClick
private void Tree_One_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
SetSelectedItem();
}
So just for clarity, the node that I right click does not get selected like expected. What am I doing wrong and how can I fix it?
UPDATE:
I think I know what the problem is after playing around with the answer below. The code I have in this question doesn't actually change the selected item, it just kind of reiterates through the selection of the currently selected item, re-selecting it. If there was a way to actually change the selected item to the item that is right clicked, it would run perfectly. Any clue on how to do something like that?
The answer by #alex2k8 on this question is exactly what I was looking for, and is what I used to solve my problem.
Thanks to anyone who helped out.
sorry for my bad englisch.
Well I'm working with the MS VS 2017 Version 15.9.1.
So - all your ways for selected a treeviewItem via right mouse click dosn't work - I don't know why.
But I find a working way:
private void Treeview1_MouseRightButtonDown(object sender, MouseButtonEventArgs e){
// The source from the Mouse Event Args is a TreeViewItem.
var treeViewitem = e.Source as TreeViewItem;
// Than works your Code in the above Posts!
if (treeViewitem != null)
{
treeViewitem.IsSelected = true;
e.Handled = true;
}
}
cu
Marc
Please see the sample snippet below wich is able to get the selected item
public partial class MainWindow : Window
{
public List<Item> Items { get; set; }
public MainWindow()
{
InitializeComponent();
Items = new List<Item>();
for (int i = 0; i < 10; i++)
{
Items.Add(new Item() {ItemName="Item " + i.ToString() });
}
this.DataContext = this;
}
private void TreeView1_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
if ((sender as TreeView).SelectedItem != null)
{
Item itm = (Item)(sender as TreeView).SelectedItem;
Console.WriteLine(itm.ItemName);
}
}
}
public class Item
{
public string ItemName { get; set; }
}
XAML
<TreeView Name="TreeView1" MouseRightButtonDown="TreeView1_MouseRightButtonDown" ItemsSource="{Binding Items}">
<TreeView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ItemName}" />
</DataTemplate>
</TreeView.ItemTemplate>
</TreeView>
This might be a bit outdated but I just found a very nice solution to this. At least imo.
TreeView now supports a NodeMouseClick event in which you can select the clicked node.
private void treeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
this.treeView.SelectedNode = e.Node;