.NET 4.0 DataGridCombobox SelectionChanged issue - datagrid

I have a requirement in my program that the object bound (from ViewModel) in a Combobox is updated as soon as an item is selected in the combobox. Currently, the object only updates once the edit is committed by either pressing Enter or leaving the cell. The user does not want the extra step.
My thought would be to have the act of selecting an item in the combobox trigger the CommitEdit() method and then CancelEdit(). However, I cannot seem to find a way to hook into the SelectionChanged event for the DataGridComboBoxColumn as it is not available.
Other suggestions have been to listen in the viewmodel for a property change event but the property is not changed until the Cell Edit is finished.
Can anyone think of a way to cause the selection of a new item (index) in a DataGridCombobox to close the edit of the cell as if the user pressed Enter or left the cell?
NOTE: I cannot use .NET 4.5 due to customer limitations.

I've had similar issue but i just found out the solution using attached property, This may not exactly fix your problem but it will help in datagrid selection changed issue.
Below is the attached property and handler methods
public static readonly DependencyProperty ComboBoxSelectionChangedProperty = DependencyProperty.RegisterAttached("ComboBoxSelectionChangedCommand",
typeof(ICommand),
typeof(SpDataGrid),
new PropertyMetadata(new PropertyChangedCallback(AttachOrRemoveDataGridEvent)));
public static void AttachOrRemoveDataGridEvent(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
DataGrid dataGrid = obj as DataGrid;
if (dataGrid != null)
{
if (args.Property == ComboBoxSelectionChangedProperty)
{
dataGrid.SelectionChanged += OnComboBoxSelectionChanged;
}
}
else if (args.OldValue != null && args.NewValue == null)
{ if (args.Property == ComboBoxSelectionChangedProperty)
{
dataGrid.SelectionChanged -= OnComboBoxSelectionChanged;
}
}
}
private static void OnComboBoxSelectionChanged(object sender, SelectionChangedEventArgs args)
{
DependencyObject obj = sender as DependencyObject;
ICommand cmd = (ICommand)obj.GetValue(ComboBoxSelectionChangedProperty);
DataGrid grid = sender as DataGrid;
if (args.OriginalSource is ComboBox)
{
if (grid.CurrentCell.Item != DependencyProperty.UnsetValue)
{
//grid.CommitEdit(DataGridEditingUnit.Row, true);
ExecuteCommand(cmd, grid.CurrentCell.Item);
}
}
}
SpDataGrid is the custom control that i inherited from data grid.
I added below style in generic.xaml as i use the resourcedictionary for style (you can certainly add inside the datagrid).
<Style TargetType="{x:Type Custom:SpDataGrid}">
<Setter Property="Custom:SpDataGrid.ComboBoxSelectionChangedCommand" Value="{Binding ComboBoxSelectionChanged}"/>
</Style>
ComboBoxSelectionChanged is the command in my viewmodel. OnComboBoxSelectionChanged i commented the commitedit because in my case the values were already updated.
Let me know if anything is not clear or any questions. Hope this helps.

Related

Xamarin forms template switch native content remains

I am seeing something strange where an instance of ContentView from a ControlTemplate affects how another instance of the ContentView looks, under the same page, from another ControlTemplate.
ContentView BLA:
ScrollView
L Accordion control
L Accordion Item
Control template A:
BLA
Control template B:
Tab control
L Tab 1 Content: BLA
L Tab 2 Content: other
Somehow switching ControlTemplate from A to B, B to A,
And the height of the accordion item remain from the first template.
It is not the same instance.
How can I make sure the native controls are disposed of when switching ControlTemplate?
Normally, we use DataTemplateSelector to switch templates.
For the Limitations in the MSdocs, the warnings, however the reason behind it, is due to the caching of templates in the renderer. If you change it up, the previous template will be cached in the renderer and there will be no longer any way to reference or dispose of it, until the ListView is disposed of. Hence as you scroll, it will continue to cache new templates and never free up the old ones.
Hope this would be helpful to you.
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/templates/data-templates/selector
I moved away from template switching as the template is being cached, meaning the last view is still in memory, and this causes all kind of problems such as binding errors and layout measures turning out wrong.
I now use MyView which inherits ContentView:
public class MyView : ContentView
{
public static readonly BindableProperty DataProperty =
BindableProperty.Create(nameof(Data), typeof(object), typeof(MyView ), null, propertyChanging: OnDataPropertyChanging);
public object Data
{
get => (object)GetValue(DataProperty);
set => SetValue(DataProperty, value);
}
private static void OnDataPropertyChanging(BindableObject bindable, object oldValue, object newValue)
{
var instance = bindable as MyViewModel;
instance.Content = null;
if (newValue == null)
{
return;
}
var type = newValue.GetType();
View view = null;
if (type == typeof(MyViewModel1))
{
view = new BLA();
}
else if (type == typeof(MyViewModel2))
{
view = new other();
}
if (view != null)
{
view.BindingContext = newValue;
instance.Content = view;
}
}
}

Adding children to StackLayout inside for loop causes this error "Layout cycle detected. Layout could not complete." in Xamarin Forms UWP

foreach (var equipment in EquipmentCollection)
{
var control = new EquipmentControl(equipment);
MyStackLayout.Children.Add(control);
}
I am getting this error only in UWP but not in Android. Even in UWP if the list size is small it is working fine.
I have tried few work arounds but still I couldn't able to make it work.
Since there is no UpdateLayout() method for xamarin-forms controls so I tried to use custom renderer for stacklayout and raised a child added event and called UpdateLayout() inside it but still got the crash.
[assembly: ExportRenderer(typeof(CustomStackLayout), typeof(CustomStackLayoutRenderer))]
namespace FO4.UWP.Controls
{
public class CustomStackLayoutRenderer : ViewRenderer<StackLayout, StackPanel>
{
StackPanel stkPanel;
protected override void OnElementChanged(ElementChangedEventArgs<StackLayout> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
CustomStackLayout stkLayout = (CustomStackLayout)e.NewElement;
stkLayout.ChildAdded += StkLayout_ChildAdded;
}
if (e.OldElement != null)
{
CustomStackLayout stkLayout = (CustomStackLayout)e.OldElement;
stkLayout.ChildAdded -= StkLayout_ChildAdded;
}
}
private void StkLayout_ChildAdded(object sender, ElementEventArgs e)
{
this.UpdateLayout();
}
}
}
I develop in Xamarin Forms but I don't target UWP.
Here some suggestions that will maybe help you:
For this kind of need, it is more frequent to use DataBinding through BindableLayout.ItemTemplate and Bindable.ItemsSource like described here: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/layouts/bindable-layouts#populate-a-bindable-layout-with-data.
If you don't want to use these mechanism, maybe you can try to use the BatchBegin() and BatchCompleted() method before and after your Loop https://learn.microsoft.com/en-us/dotnet/api/xamarin.forms.visualelement.batchbegin?view=xamarin-forms
The use of a renderer shoud not be required in my opinion...

Get e parameter from a button that hasn't been clicked

Is there a way that I could access the e event arguments for a button that has not been clicked?
I need to delete multiple entries in a gridview by clicking a button and having it simulate clicking the delete button for each selected entry, but I can't use performClick, so I'm trying to call the actual method that deletes each one. However, that method requires an "e As System.Web.UI.WebControls.GridViewCommandEventArgs" parameter and I can't figure out how to get that.
You won't be able to access the EventArgs parameter.
I'd suggest you design your code like this:
public class MyClass
{
private ListView listView;
protected void OnClick(EventArgs e)
{
performAction();
}
private void performAction()
{
listView.deleteSelectedItems();
}
}
Don't implement functionality you are going to need somewhere else in delegates. Instead call this functionality inside the delegates' body. This way you can reuse performAction() somewhere else ..
Your problem calling delete button can be resolved if you add one check box in each row of datagrid and on click of button Delete you can perform delete operation for the checked rows in following manner
Protected void btnDelete_Click(object sender, EventArgs e)
{
for(int i = 0; i < GridView1.Rows.Count; i++)
{
CheckBox chkDelete = (CheckBox)GridView1.Rows[i].Cells[0].FindControl("chkSelect");
if(chkDelete != null)
{
if(chkDelete.Checked)
{
strID = GridView1.Rows[i].Cells[1].Text;
ids.Add(strID); //ids can colletion of any type
}
}
}
}
Now send ids to any function to perform delete.

Add drop down menu on button click - windows 8

I want to display a drop down menu when a user clicks a button. Something like comboBox but instead of the comboBox its a button. How can I do it??
I solved it using PopupMenu. Here is the code for other's reference.
public static Rect GetElementRect(FrameworkElement element)
{
GeneralTransform buttonTransform = element.TransformToVisual(null);
Point point = buttonTransform.TransformPoint(new Point());
return new Rect(point, new Size(element.ActualWidth, element.ActualHeight));
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
var menu = new PopupMenu();
menu.Commands.Add(new UICommand("Label", (command) =>
{
//do work
}));
// We don't want to obscure content, so pass in a rectangle representing the sender of the context menu event.
// We registered command callbacks; no need to handle the menu completion event
var chosenCommand = await menu.ShowForSelectionAsync(GetElementRect((FrameworkElement)sender));
if (chosenCommand == null) // The command is null if no command was invoked.
{
}
}
Milan,
You'll need to create a custom control or a user control that combines a button and a popup. You could also just implement this in-place with a button and popup. I suggest you look at Callisto's Menu control and start from there to implement your dropdown menu:
Callisto controls (includes a Menu)

ItemClick Event in a flex Combobox

Does anyone know, is there any way to catch ItemClick Event in a Flex ComboBox (or anything similar). Maybe there's any trick .. :) I do realize, that I can customize it, but this not suits my case.
Thanks for your time :)
As you can see in mx:ComboBox sources, the function, creating the dropdown list, is private, the listener to ITEM_CLICK is private and the list itself is also private:
private var _dropdown:ListBase;
private function getDropdown():ListBase
{
// ...
_dropdown = dropdownFactory.newInstance();
// ...
_dropdown.addEventListener(ListEvent.ITEM_CLICK, dropdown_itemClickHandler);
// ....
}
private function dropdown_itemClickHandler(event:ListEvent):void
{
if (_showingDropdown)
{
close();
}
}
So you can not even extend ComboBox.
The only public thing is dropdownFactory, which theoretically can be overriden to somehow register the created dropdown list or create extended list. But the problem I see is that ComboBox is not the parent of dropdown list - PopupManager is. This can make dispatching (bubble) events quite difficult.
I think the following document will be helpful
ItemClick event in flex List
I found this solution. I just want a spark dropdownlist with itemClick event and without itemselect option (don't show selected item label on button)
[Event(name="itemClick", type="mx.events.ItemClickEvent")]
public class ItemClickDropDownList extends DropDownList
{
public function ItemClickDropDownList()
{
super();
}
override public function closeDropDown(commit:Boolean):void
{
super.closeDropDown(commit);
var e:ItemClickEvent = new ItemClickEvent(ItemClickEvent.ITEM_CLICK, true);
e.item = this.selectedItem;
e.index = this.selectedIndex;
dispatchEvent(e);
//Deselect item
this.selectedIndex = -1;
}

Resources