c# - instancelocator - xamarin stacklayout content binding
¿Cómo seleccionar una fila en la cuadrícula de datos de ViewModel en MVVM? (2)
Estoy tratando de validar la entrada del usuario en una cuadrícula de datos, la forma en que lo hago es como:
I) Permitir al usuario agregar una fila
II) permite al usuario llenar algunas celdas
III) cuando ocurre el evento EndEdit (), actualizaría mi modelo
IV) si el Modelo no se pudo actualizar (por ejemplo, cuando el usuario no suministró valores NotNull), se genera un error.
V) ¡AQUÍ ESTÁ LA PARTE TRILLY! Quiero permanecer en la fila defectuosa de la cuadrícula de datos, pero la fila muy iluminada cambiará a pesar del hecho de que he establecido SelectedIndex y SelectedValue correctamente.
aquí está mi XAML:
<DataGrid x:Name="gd_Contacts" SelectedItem="{Binding SelectedContact,Converter={StaticResource NewPlaceConverter}}"
SelectedIndex="{Binding SelectedItemIndex}"
Margin="0,5,1,0" ItemsSource="{Binding ContactCollection, Mode=TwoWay}"
CanUserAddRows="True" CanUserDeleteRows="False" AutoGenerateColumns="False" Grid.Column="1">
Aquí está mi ViewModel:
private ObservableCollection<ActionEnabledContacts> FContactCollection;
//....
public ActionEnabledContacts SelectedContact //THE PROPERTY FOR SELECTEDITEM
{
get { return FSelectedContact; }
set
{
//
List <ActionEnabledContacts> InvalidList=ContactCollection.Where<ActionEnabledContacts>(p => p.cnt_Key == 0).ToList();
if (InvalidList != null && InvalidList.Count > 0)
{
//now find index of that bastard
List<ActionEnabledContacts> AllContacts = ContactCollection.ToList();
int BastardIndex = 0;
foreach (ActionEnabledContacts AContact in AllContacts)
{
if (AContact.cnt_Key == 0)
{
FSelectedContact = InvalidList[0];
NotifyPropertyChanged();
SelectedItemIndex = BastardIndex;
//^^^^ THIS LINE DO UPDATE SELECTEDINDEX AND CALL NotifyPropertyChanged()
}
BastardIndex++;
}
}
else
{
//
FSelectedContact = value;
NotifyPropertyChanged();
}
}
}
No puede cambiar la selección mientras la selección está cambiando ... Si eso tiene algún sentido: P
Si la selección acaba de cambiar, tendrá que esperar hasta que pueda cambiarla programáticamente una vez más. Esto normalmente se haría usando Dispatcher.BeginInvoke
para agregar su llamada a la cola Dispatcher, para que se ejecute luego de que se procese la selección actual.
if (AContact.cnt_Key == 0)
{
FSelectedContact = InvalidList[0];
NotifyPropertyChanged();
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
SelectedItemIndex = BastardIndex));
}
BastardIndex++;
Sin embargo, hacer esto en su modelo de vista no es exactamente la mejor solución, ya sea MVVM o en múltiples escenarios de subprocesos de UI. Simplemente puede generar un evento en esa línea (pasando el índice dentro de EventArgs
), hacer que su vista se suscriba a ese evento y this.Dispatcher
la llamada de Dispatcher desde el controlador de eventos (usando this.Dispatcher
lugar de Application.Current.Dispatcher
).
Gracias a @almulo, he implementado un evento en el ViewModel y el controlador correspondiente en View y funciona como un hechizo, para cualquiera que necesite ayuda al respecto, estos son los pasos:
I) en ViewModel agregue un evento como este:
public event EventHandler<EventArg<int>> DataGridRowSelectionChange;
* tenga en cuenta que EventArg es simplemente una clase simple que puede contener un valor de tipo T de la siguiente manera:
public class EventArg<T> : EventArgs
{
private T FEventData;
public EventArg(T Param)
{
// TODO: Complete member initialization
FEventData = Param;
}
public T EventData
{
get { return FEventData; }
set { FEventData = value; }
}
}
II) en ViewModel cada vez que quiera cambiar la fila seleccionada :
if (DataGridRowSelectionChange != null)
DataGridRowSelectionChange(this, new EventArg<int>(DesiredIndex));
III) en el constructor Ver agrega el controlador de eventos , así:
((YourViewModelClass)DataContext).DataGridRowSelectionChange += CurrentViewModel_DataGridRowSelectionChange_EventHandler;
IV) y finalmente escribe el controlador en la vista de esta manera:
void CurrentViewModel_DataGridRowSelectionChange_EventHandler(object sender, EventArg<int> e)
{
Dispatcher.BeginInvoke(new Action(() => GRIDNAME.SelectedIndex = e.EventData));
}
y eso es todo :)