Thanks,
Chris
9 Answers, 1 is accepted
Currently the RadListBox control doesn't provide any way to manipulate the selected items in a MVVM friendly scenario. What I could suggest is to use the SelectionChanged property and in the handler you can get the RadListBox.SelectedItems property (it has only a getter and no setter). We consider this as a feature request and we logged it in our backlog system. You could vote for it and observe its progress here -
http://www.telerik.com/support/pits.aspx#/public/silverlight/9902
George
the Telerik team
I do have a similar work
around, I was just hoping the control had the feature and I was missing it.
That I did was attached a trigger, and using MVVMLight's EventToCommand
mapped that to my ViewModel. in the ViewModel I assign the selected items
to a collection...
My trigger (on the listbox):
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<mvvm:EventToCommand Command="{Binding MethodChangedCommand}" CommandParameter="{Binding SelectedItems, ElementName=callMethodListBox}" />
</i:EventTrigger>
</i:Interaction.Triggers>Then in my ViewModel:
MethodChangedCommand = new RelayCommand<IList>(items =>{ _selectedCallMethods.Clear();foreach (var item in items) _selectedCallMethods.Add(item as NameValueViewModel<int>);
});I'm still pretty new to MVVM, and there is probably a more elegant way to accomplish this, if others have a better way please feel free to share!
I found one solution for myself - but it's not "pure" MVVM.
In VM:
public Action OnSelectFirstDocumentType;private void LoadDocumentTypesComleted(LoadOperation<DocumentType> obj){ ... ...load content of listbox ... if (DocumentTypes.Count > 0) { OnSelectFirstDocumentType(); }}public partial class AddEditDocumentView { public AddEditDocumentView() { InitializeComponent(); this.Loaded += new System.Windows.RoutedEventHandler(AddEditDocumentView_Loaded); } void AddEditDocumentView_Loaded(object sender, System.Windows.RoutedEventArgs e) { //handler - select first item in type's listbox if (this.DataContext as AddEditDocumentViewModel != null) { (this.DataContext as AddEditDocumentViewModel).OnSelectFirstDocumentType = (() => { if (DocTypeListBox.Items.Count > 0) { DocTypeListBox.SelectedIndex = 0; } }); } } }public Action<int> OnSelectFirstDocumentType; or
public Action<object> OnSelectFirstDocumentType; and send index or item to select (and select it in handler in view).
I'm using an attached property for this scenario:
using System.Collections;using System.Windows;using Telerik.Windows.Controls;namespace test{ /// <summary> /// This class allow to bind selected Items from ListBox. /// </summary> public static class SelectedItemsHelperRadListBox { /// <summary> /// SelectedItems Attached Dependency Property. /// </summary> public static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.RegisterAttached("MySelectedItems", typeof(IList), typeof(SelectedItemsHelperRadListBox), new FrameworkPropertyMetadata((IList)null, new PropertyChangedCallback(OnSelectedItemsChanged))); /// <summary> /// Gets my selected items. /// </summary> /// <param name="d">The d.</param> /// <returns></returns> public static IList GetMySelectedItems(DependencyObject d) { return (IList)d.GetValue(SelectedItemsProperty); } /// <summary> /// Sets my selected items. /// </summary> /// <param name="d">The d.</param> /// <param name="value">The value.</param> public static void SetMySelectedItems(DependencyObject d, IList value) { d.SetValue(SelectedItemsProperty, value); } /// <summary> /// Called when [selected items changed]. /// </summary> /// <param name="sender">The sender.</param> /// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param> private static void OnSelectedItemsChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { var listBox = sender as RadListBox; if (listBox != null) { ReSetSelectedItems(listBox); listBox.SelectionChanged += delegate { ReSetSelectedItems(listBox); }; } } /// <summary> /// Res the set selected items. /// </summary> /// <param name="listBox">The list box.</param> private static void ReSetSelectedItems(RadListBox listBox) { IList selectedItems = GetMySelectedItems(listBox); if (selectedItems != null) { selectedItems.Clear(); if (listBox.SelectedItems != null) { foreach (var item in listBox.SelectedItems) { selectedItems.Add(item); } } } } }<telerik:RadListBox x:Name="xxx" Grid.Row="1" Helper:SelectedItemsHelperRadListBox.MySelectedItems="{Binding SelectedDatas}" ItemsSource="{Binding Datas}" SelectionMode="Extended" Margin="0,5,0,0"></<telerik:RadListBox>It does the job for me.
++
http://blogs.telerik.com/vladimirenchev/posts/10-05-31/how-to-synchronize-your-ui-selected-items-with-your-data-context-using-mvvm-and-blend-behaviors-for-silverlight-and-wpf.aspx
to work with the RadListBox:
public class RadListBoxSelectedItemsBehavior : Behavior<RadListBox>{ private RadListBox ListBox { get { return AssociatedObject; } } public INotifyCollectionChanged SelectedItems { get { return (INotifyCollectionChanged)GetValue(SelectedItemsProperty); } set { SetValue(SelectedItemsProperty, value); } } public static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.Register("SelectedItems", typeof(INotifyCollectionChanged), typeof(RadListBoxSelectedItemsBehavior), new PropertyMetadata(OnSelectedItemsPropertyChanged)); private static void OnSelectedItemsPropertyChanged(DependencyObject target, DependencyPropertyChangedEventArgs args) { var collection = args.NewValue as INotifyCollectionChanged; if (collection != null) { collection.CollectionChanged += ((RadListBoxSelectedItemsBehavior)target).ContextSelectedItemsCollectionChanged; } } protected override void OnAttached() { base.OnAttached(); ListBox.SelectionChanged += ListBoxOnSelectionChanged; } private void ContextSelectedItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { UnsubscribeFromEvents(); Transfer(SelectedItems as IList, ListBox.SelectedItems); SubscribeToEvents(); } private void ListBoxOnSelectionChanged(object sender, SelectionChangedEventArgs selectionChangedEventArgs) { UnsubscribeFromEvents(); Transfer(ListBox.SelectedItems, SelectedItems as IList); SubscribeToEvents(); } private void SubscribeToEvents() { ListBox.SelectionChanged += ListBoxOnSelectionChanged; if (SelectedItems != null) { SelectedItems.CollectionChanged += ContextSelectedItemsCollectionChanged; } } private void UnsubscribeFromEvents() { ListBox.SelectionChanged -= ListBoxOnSelectionChanged; if (SelectedItems != null) { SelectedItems.CollectionChanged -= ContextSelectedItemsCollectionChanged; } } public static void Transfer(IList source, IList target) { if (source == null || target == null) return; target.Clear(); foreach (var o in source) { target.Add(o); } }}I have a collection in an object and I want to edit my object in a RadDataForm.
This is how I solved it:
1. I added two DependencyProperties to my class derived from DataFormDataField: Population (all selectable items) and SelectedItems (which was bound to THE collection).
2. Since the items of a RadListBox cannot be selected programmatically (correct me if I'm wrong), I created an ItemTemplate with a checkbox.
3. The ListBox.ItemsSource I bound to my Population (via a MultiValueConverter).
4. In this converter I combined both the DependencyProperties and created a List of objects with a Selected property (which was bound to the IsChecked property of the checkbox).
5. To the checkbox I added two handlers for the Checked and Unchecked event. In here I added and removed items to and from the SelectedItems property.
That's it. I hope this is useful to someone.