Jeżeli w Silverlight chcemy posortować sobie ListBox za pomocą przeciągania elementów – dosłownie mówiąc na liście mamy 10 elementów i chcemy zamienić element 1 z 6 – możemy to zrobić w bardzo prosty sposób z wykorzystaniem kontrolki ListBoxDragDropTarget dostępnej w Silverlight Toolkit. By to osiągnąć należy naszą kontrolkę ListBox opakować w ListBoxDragDropTarget, następnie ustawić ItemsPanelTemplate dla ListBox na StackPanel – jest to spowodowane tym, że ListBox używa VirtualizedStackPanel, przez co nie może on określić indeksu elementu na liście, zamiana na StackPanel załatwia problem.
Uwaga: w kodzie zakładam, że korzystamy z MVVM oraz MVVM Toolkit Light. ElementName odwołuje się nazwy kontrolki.
Kod powinien wyglądać tak:
<UserControl.Resources> <DataTemplate x:Key="ActiveLayerListBoxItemDataTemplate" > <StackPanel Orientation="Horizontal" Margin="7" HorizontalAlignment="Stretch" ToolTipService.ToolTip="{Binding Path=Name, StringFormat='{0} Active Layer'}"> <ContentPresenter Content="{Binding Path=Icon, Mode=OneTime}" Width="16" Height="16"/> <TextBlock Text="{Binding Path=Name}" /> </StackPanel> </DataTemplate> </UserControl.Resources> <!-- kod wyciety --> <toolkit:ListBoxDragDropTarget AllowDrop="True" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch"> <i:Interaction.Triggers> <i:EventTrigger EventName="ItemDragCompleted"> <cmd:EventToCommand Command="{Binding ElementName=ActiveLayersViewControl, Path=DataContext.ActiveLayersReOrderedCommand, Mode=OneWay}" CommandParameter="{Binding .}" /> <!--<ia:CallMethodAction MethodName="ReorderList" TargetObject="{Binding}" />--> </i:EventTrigger> </i:Interaction.Triggers> <ListBox x:Name="SelectedLayersListBox" ItemsSource="{Binding Path=SelectedLayers, Mode=TwoWay}" ItemTemplate="{StaticResource ActiveLayerListBoxItemDataTemplate}" SelectionMode="Extended" > <ListBox.ItemsPanel> <ItemsPanelTemplate> <StackPanel /> </ItemsPanelTemplate> </ListBox.ItemsPanel> </ListBox> </toolkit:ListBoxDragDropTarget>
Teraz by dobrać się do posortowanych elementów, musimy wykonać jeszcze jedną dodatkową czynność. Obsłużyć zdarzenie ItemDragCompleted – kiedy ono zachodzi, możemy bezproblemowo odwołać się do naszej listy i sprawdzić kolejność/wysłać wiadomość o zaistniałym fakcie/zapisać zmiany:
// RelayCommand i Messenger pochodza z MVVM Toolkit Light public RelayCommand ActiveLayersReOrderedCommand { get; private set; } // ... ActiveLayersReOrderedCommand = new RelayCommand(() => Messenger.Default.Send(new LayersOrderChangedMessage(SelectedLayers.Select(x => x.Id).ToList())) );