UWP Drag and Drop between Multiple ListViews - c#

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

Related

Xamarin Forms. How can I bind picker's selected item to be displayed in picker field on switching view?

I'm having problem with picker's bindable SelectedItem and ItemsSource, when I have a picker filled with values from database.
On pushing view with binding context as a class,
async private void ListaRachunkow_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
if (e.SelectedItem != null)
{
await Navigation.PushModalAsync(new RachunekDetails() { BindingContext = e.SelectedItem as Rachunek });
}
}
with picker being one of the fields,
<Picker x:Name="kategoriaPicker" SelectedItem="{Binding Kategoria}" Grid.Row="0" Grid.Column="1"/>
there is no selected item appearing (empty field). Pikcer is being filled with list gathered from another class's database.
protected override void OnAppearing()
{
base.OnAppearing();
PopulatePicker();
}
async private void PopulatePicker()
{
List<Kategorie> kategories = await App.KategoriaDatabase.GetKategorieAsync();
List<string> katestringlist = new List<string>();
foreach (Kategorie k in kategories)
katestringlist.Add(k.NazwaKategorii.ToString());
kategoriaPicker.ItemsSource = katestringlist;
}
Kategorie class has 2 fields. one is its integer ID, the other one is its name. I am stuck in here, trying to figure out how to solve this issue, but I can't find any solution.
What this part of app does is that there is a listview filled with items from Rachunek's class database. If an item is selected, it pushes this item to new view where you can edit it or delete it.
What I dont understand is that there is a second picker that is filled statically in view constructor methode, below InitializeComponent(), is bound in the same way and works perfectly.
typPlatnosciPicker.ItemsSource= new List<string>{
"Karta",
"Gotówka",
"Inny"
};
Target platform is Android.

Set Default Value for ListBox

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();

UWP ListView Drag and Drop

I am going to drag an item from a ListView to drop a box to process something.
In this case, I am not able to get selected ListView item. Selected Index/Items always returns -1/null.
Note: I am able to get selected listview item when using SelectionChanged.
But not able to get drop event. Please advise.
The XAML source:
<ListView x:Name="lvMaster" CanDragItems="True" SelectionChanged="lvMaster_SelectionChanged" />
<Grid AllowDrop="True" Drop="Drop_Event" DragOver="DragOver_Event">
</Grid>
The C# source:
private void Drop_Event(object sender, DragEventArgs e)
{
lvObj = new ListView();
ListView)sender;
}
private void DragOver_Event(object sender, DragEventArgs e)
{
AcceptedOperation = DataPackageOperation.Copy;
DragUIOverride.IsCaptionVisible = true;
DragUIOverride.IsContentVisible = true;
}
You can register DragItemsStarting event or DragItemsCompleted event for your listview, then in its handler method, you could get all items you dragged.
private void SourceListView_DragItemsCompleted(ListViewBase sender, DragItemsCompletedEventArgs args)
{
var cc = args.Items;
}
Please refer to the official Drag and Drop sample for more details.
Please

Operation is not valid while ItemsSource is in use. Access and modify elements with ItemsControl.ItemsSource

I'm trying to make 2 list boxes where I can press on a button to add an item selected from the left listbox to the right listbox. Here's the XAML for the listboxes:
<ListBox
x:Name="LeftList"
Foreground="{StaticResource Foreground}"
HorizontalAlignment="Left"
Height="237" Margin="15,103,0,0"
VerticalAlignment="Top"
Width="128">
<ListBoxItem>360T</ListBoxItem>
<ListBoxItem>BARX</ListBoxItem>
<ListBoxItem>BNP</ListBoxItem>
<ListBoxItem>BOA</ListBoxItem>
<ListBoxItem>CITI</ListBoxItem>
<ListBoxItem>CS</ListBoxItem>
<ListBoxItem>DB</ListBoxItem>
<ListBoxItem>GS</ListBoxItem>
<ListBoxItem>JPM</ListBoxItem>
<ListBoxItem>RBS</ListBoxItem>
<ListBoxItem>UBS</ListBoxItem>
</ListBox>
<ListBox
x:Name="RightList"
Foreground="{StaticResource Foreground}"
HorizontalAlignment="Left"
Height="237" Margin="257,103,0,0"
VerticalAlignment="Top"
Width="128"/>
C#:
List<string> leftSideList = new List<string>();
List<string> rightSideList = new List<string>();
public ChooseLPWindow()
{
InitializeComponent();
//Add to the collection leftside list
leftSideList.Add("360T");
leftSideList.Add("BARX");
leftSideList.Add("BNP");
leftSideList.Add("BOA");
leftSideList.Add("CITI");
leftSideList.Add("CS");
leftSideList.Add("DB");
leftSideList.Add("GS");
leftSideList.Add("JPM");
leftSideList.Add("RBS");
leftSideList.Add("UBS");
}
private void AddBtn_Click(object sender, RoutedEventArgs e)
{
if (LeftList.SelectedIndex > -1)
{
int SelectedIndex = LeftList.SelectedIndex;
string SelectedItem = LeftList.SelectedValue.ToString();
//Add the selected item to the right side list
RightList.Items.Add(SelectedItem);
rightSideList.Add(SelectedItem);
if (leftSideList != null)
{
//Remove the item from the collection list
leftSideList.RemoveAt(SelectedIndex);
//Update the left side list
LeftList.Items.Clear();
LeftList.ItemsSource = leftSideList;
}
}
}
I get the exception on:
LeftList.Items.Clear();
This happens when I try to add a second item the first one gets added but then the exception occurs when you try to add another item. The error is:
Operation is not valid while ItemsSource is in use. Access and modify elements with ItemsControl.ItemsSource
Any suggestions?
You can't modify ListBox's Items when the items populated through ItemsSource. In that case you suppose to modify items in the ItemsSource collection instead.
I'd suggest to change your List to ObservableCollection. With that removing item from collection is enough, because ObservableCollection has built-in mechanism to notify UI to refresh whenever item added or removed from collection :
ObservableCollection<string> leftSideList = new ObservableCollection<string>();
ObservableCollection<string> rightSideList = new ObservableCollection<string>();
public ChooseLPWindow()
{
InitializeComponent();
leftSideList.Add("360T");
leftSideList.Add("BARX");
leftSideList.Add("BNP");
leftSideList.Add("BOA");
leftSideList.Add("CITI");
leftSideList.Add("CS");
leftSideList.Add("DB");
leftSideList.Add("GS");
leftSideList.Add("JPM");
leftSideList.Add("RBS");
leftSideList.Add("UBS");
LeftList.ItemsSource = leftSideList;
}
private void AddBtn_Click(object sender, RoutedEventArgs e)
{
if (LeftList.SelectedIndex > -1)
{
int SelectedIndex = LeftList.SelectedIndex;
string SelectedItem = LeftList.SelectedValue.ToString();
//Add the selected item to the right side list
RightList.Items.Add(SelectedItem);
rightSideList.Add(SelectedItem);
if (leftSideList != null)
{
//Remove the item from the ItemsSource collection
//instead of removing it from ListBox.Items
leftSideList.RemoveAt(SelectedIndex);
}
}
}
I fixed the issue by doing this:
private void AddBtn_Click(object sender, RoutedEventArgs e)
{
if (LeftList.SelectedIndex > -1)
{
int SelectedIndex = LeftList.SelectedIndex;
string SelectedItem = LeftList.SelectedValue.ToString();
//Add the selected item to the right side list
RightList.Items.Add(SelectedItem);
rightSideList.Add(SelectedItem);
//Delete the item from the left side list
//ListLps.Items.RemoveAt(SelectedIndex);
if (leftSideList != null)
{
//Remove the item from the collection list
leftSideList.RemoveAt(SelectedIndex);
LeftList.Items.RemoveAt(SelectedIndex);
}
}
}

How to find components in listbox item, in Windows Phone?

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;
}

Categories