DragDropManager How to prevent from adding incoming element to list? - c#

Currently my page consist of two grid side by side, each of the grid binding a list, says GridA binding ListA and GridB binding ListB.
Both of the grid implemented Telerik DragDropManager. In most cases everything works fine, user can simply drag element from GridA and drop on GridB and both ListA and ListB will reflect accordingly.
Now I'm trying to make a checking on GridB so that whenever user drag an element from GridA, if this element existed in GridB, the element won't be added.
I noticed I can implement a drop function at GridB as below:
<telerik:RadGridView
ItemSource="{Binding ListB}"
DataContext="{Binding [someViewModel]}"
Drop="abc_Drop"
DataLoaded="abc_DataLoaded"
x:Name="GridB">
And below will be my drop function:
private void abc_Drop(object sender, System.Windows.DragEventArgs e)
{
var selectedItem = (T)GridA.SelectedItem;
List<T> x = someViewModel.ListB;
}
In order to investigate, I put a breakpoint on abc_Drop method. What I found is that, while I execute abc_Drop method, someViewMode.ListB.Count() still return 0 but once it finish, someViewModel.ListB.Count() return 1. Hence my question, where should I do the checking and prevent element added into the list conditionally? What will be executed right after drop method?

I've found the answer myself.
private void abc_Drop(object sender, System.Windows.DragEventArgs e){
e.Handled = true;
var selectedItem = (T)GridA.SelectedItem;
if( /*condition*/ ){
ListB.Add(selectedItem);
}
GridB.Rebind();
}
By using e.Handled = true, it halted the operation and I can now implement my own logic into it

Related

C# WinForms ListBox changes selection to first item

I got a problem with a ListBox in a WinForm application. I have two ListBoxes inside of a tab control and depending on the selection in the first one (lb1), the DataSource of the second one (lb2) changes. This is done in the SelectedValueChanged Event.
private void listBox_ControlUnits_SelectedValueChanged(object sender, EventArgs e)
{
ControlUnit unit = (sender as ListBox).SelectedItem as ControlUnit;
textBox_ProjectNameTab.Text = unit.ProjectName;
listBox_ControlCircuits.DataSource = null;
listBox_ControlCircuits.DataSource = unit.ControlCircuits;
}
lb1 is filled with a DataSource, too.
Now if I select a value in lb1 the selection automatically jumps back to the first item and I can not figure out why. is this some kind of UI update problem?
Even without the SelectedValueChanged event and the connection to the second listbox the issue occures.
Short gif of the problem, sorry for the blurriness
If I select one item more than once it works somehow (as seen in the gif).
Edit:
I found the problem but I do not quite understand what happens.
I have another listBox on another tab of my tab control. This listBox has the same DataSource as lb1. This seems to cause this behavior.
I finally found the problem:
I did not know that if I use the same DataSource for two ListBoxes they share the BindingContext per default.
I created a new BindingContext for the second ListBox and now the selection does no longer change.
listBox_allGroups.DataSource = null;
listBox_allGroups.DataSource = x.y;
listBox_allGroups.DisplayMember = "Name";
listBox_ControlUnits.DataSource = null;
listBox_ControlUnits.DataSource = x.y;
listBox_ControlUnits.DisplayMember = "Name";
listBox_ControlUnits.BindingContext = new BindingContext();
You can use a variable to hold the selected item
object _selecteditem=null;
and check it in ListBox click event.
prive void ListBox1_Click(object sender,EventArgs e)
{
if(ListBox1.SelectItem == _selecteditem) return;
// do ...
}

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

How to Add new Item to XAML Datagrid using Keyboard Tab press when last item is selected?

I have a pretty basic Datagrid XAML bound to a CollectionViewSource.
<DataGrid ItemsSource="{Binding Source={StaticResource EditingItemsCollectionViewSource}}"/>
And the Collection View Source is bound to an observable collection of very basic items with 3 numerical values. C# obviously.
I want to be able to add a new row (add a new item) at the bottom of this datagrid by pressing Tab on the keyboard when I am in the last cell of the last row.
Is this possible?
One possible solution is to programmatically set the property:
dataGrid.AllowUserToAddRows = true;
in order to implement "Add Row" functionality (provided that it was originally set to false, thus the new row was invisible). As per your task definition, it could be triggered by Tab key press (with any additional condition you may add):
private void dataGrid_PreviewKeyDown(object sender, KeyEventArgs e)
{
try
{
if (e.Key == Key.Tab)
{
e.Handled = true;
// your code
}
}
catch{}
}
You may also want to set some default values for newly created row item by adding event handling procedure:
dataGrid.InitializingNewItem += new InitializingNewItemEventHandler(dataGrid_InitNewItem);
private void dataGrid_InitNewItem(object sender, InitializingNewItemEventArgs e)
{
// your code
}
Other sample implementations of adding row to WPF DataGrid could be found here: Wpf DataGrid Add new row
Also, pertinent to your description, you can add the item to the underlying ObservableCollection, so it will automatically appear in the DataGrid.
Hope this will help. Best regards,

Categories