Save selected items when using caliburn.micro /Telerik RadGridView /Silverlight
-
03-12-2019 - |
문제
I am using Caliburn micro(1.3)/MVVM and Silverlight. When I update the itemsource RadGridView, I lose the selected items. I found a blog about implementing a behavior to save the selected items when you are implementing MVVM. I can get the selected items, but I cannot set them back once the itemsource is refreshed. Can someoneshow me how to implement this using caliburn.micro and the RadGridVIew? I think the best way to go is to create a caliburn micro convention, but I can only find a reference for creating a convention for selectedItem, not selectedItems.
Can someone show me how to accomplish this? I tried the following, but it does not work.
private static void SetRadGridSelecteditemsConventions()
{
ConventionManager
.AddElementConvention<DataControl>(DataControl.ItemsSourceProperty, "SelectedItem", "SelectionChanged")
.ApplyBinding = (viewModelType, path, property, element, convention) =>
{
ConventionManager.SetBinding(viewModelType, path, property, element, convention, DataControl.ItemsSourceProperty);
if (ConventionManager.HasBinding(element, DataControl.SelectedItemProperty))
return true;
var index = path.LastIndexOf('.');
index = index == -1 ? 0 : index + 1;
var baseName = path.Substring(index);
foreach (var selectionPath in
from potentialName in ConventionManager.DerivePotentialSelectionNames(baseName)
where viewModelType.GetProperty(potentialName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance) != null
select path.Replace(baseName, potentialName))
{
var binding = new Binding(selectionPath) { Mode = BindingMode.TwoWay };
BindingOperations.SetBinding(element, DataControl.SelectedItemProperty, binding);
}
return true;
};
}
Thanks, Stephane
해결책
You should use a behavior for this since the SelectedItems property is readonly. Telerik has an example for this, only the example is not specific for caliburn.micro. If you add the following class to your project:
public class MultiSelectBehavior : Behavior<RadGridView>
{
public INotifyCollectionChanged SelectedItems
{
get { return (INotifyCollectionChanged)GetValue(SelectedItemsProperty); }
set { SetValue(SelectedItemsProperty, value); }
}
public static readonly DependencyProperty SelectedItemsProperty =
DependencyProperty.Register("SelectedItems", typeof(INotifyCollectionChanged), typeof(MultiSelectBehavior), new PropertyMetadata(OnSelectedItemsPropertyChanged));
private static void OnSelectedItemsPropertyChanged(DependencyObject target, DependencyPropertyChangedEventArgs args)
{
var collection = args.NewValue as INotifyCollectionChanged;
if (collection != null)
{
collection.CollectionChanged += ((MultiSelectBehavior)target).ContextSelectedItems_CollectionChanged;
}
}
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.SelectedItems.CollectionChanged += GridSelectedItems_CollectionChanged;
}
void ContextSelectedItems_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
UnsubscribeFromEvents();
Transfer(SelectedItems as IList, AssociatedObject.SelectedItems);
SubscribeToEvents();
}
void GridSelectedItems_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
UnsubscribeFromEvents();
Transfer(AssociatedObject.SelectedItems, SelectedItems as IList);
SubscribeToEvents();
}
private void SubscribeToEvents()
{
AssociatedObject.SelectedItems.CollectionChanged += GridSelectedItems_CollectionChanged;
if (SelectedItems != null)
{
SelectedItems.CollectionChanged += ContextSelectedItems_CollectionChanged;
}
}
private void UnsubscribeFromEvents()
{
AssociatedObject.SelectedItems.CollectionChanged -= GridSelectedItems_CollectionChanged;
if (SelectedItems != null)
{
SelectedItems.CollectionChanged -= ContextSelectedItems_CollectionChanged;
}
}
public static void Transfer(IList source, IList target)
{
if (source == null || target == null)
return;
target.Clear();
foreach (var o in source)
{
target.Add(o);
}
}
}
This behavior takes care of the synchronization between collection RadGridView.SelectedItems and MultiSelectBehavior.SelectedItems.
Now we need to have an ObservableCollection in the ViewModel
//Collection holding the selected items
private ObservableCollection<object> selectedGridItems;
public ObservableCollection<object> SelectedGridItems
{
get
{
if (selectedGridItems == null)
selectedGridItems = new ObservableCollection<object>();
return selectedGridItems;
}
set
{
if (selectedGridItems == value) return;
selectedGridItems = value;
NotifyOfPropertyChange(() => SelectedGridItems);
}
}
//Deselect all selected items in the gridview
public void ClearSelectedGridItems()
{
SelectedGridItems.Clear();
}
Last thing is bind the behavior in the view
<telerik:RadGridView x:Name="CustomLogs" AutoGenerateColumns="true" SelectionMode="Extended">
<i:Interaction.Behaviors>
<local:MultiSelectBehavior SelectedItems="{Binding SelectedGridItems}"/>
</i:Interaction.Behaviors>
</telerik:RadGridView>
Thats it, hope it helps you!