C# WPF Drag & Drop ListBox MVVM
I want to enable drag and drop in my application to be able to create connections between components. That doesn't sound too hard, but the problem is the type of components I want connections between.
The reason I want to be able to make connections is to be able to make a graph and calculate shortest path, etc.
What I have is a ListBox with Components which are placed on a Canvas. The reason I use ListBox is to make the components selectable. I've also made them draggable.
<DataTemplate DataType="{x:Type ViewModels:DocumentViewModel}">
<DataTemplate.Resources>
<Converters:GuiSizeConverter x:Key="SizeConverter"/>
</DataTemplate.Resources>
<ListBox ItemsSource="{Binding Components}" SelectedItem="{Binding SelectedItem}" Background="Transparent"
HorizontalAlignment="Left" VerticalAlignment="Top" BorderThickness="0" Margin="0">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<Canvas ClipToBounds="True" Height="{Binding CurrentProject.Height, Converter={StaticResource SizeConverter}}"
Width="{Binding CurrentProject.Width, Converter={StaticResource SizeConverter}}">
<Canvas.Background>
<SolidColorBrush Color="{DynamicResource {x:Static SystemColors.WindowFrameColorKey}}"/>
</Canvas.Background>
</Canvas>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Grid>
<Border Background="{TemplateBinding Background}" />
<ContentPresenter/>
</Grid>
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True" />
<Condition Property="IsSelected" Value="False"/>
</MultiTrigger.Conditions>
<Setter Property="Background" Value="#8868D5FD" />
</MultiTrigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="#4468D5FD" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Utils:DraggableExtender.CanDrag" Value="True" />
<Setter Property="Canvas.Top" Value="{Binding Path=Y, Converter={StaticResource SizeConverter},Mode=TwoWay}" />
<Setter Property="Canvas.Left" Value="{Binding Path=X, Converter={StaticResource SizeConverter},Mode=TwoWay}" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</DataTemplate>
The tricky thing now though is that it is not the Components in my ViewModel I want to use drag and drop on, but components within those components. To illustrate this better, see the example picture of a train station and tracks below. I have PlaceableComponents (which are the ones that are in the listbox), i.e. the Track and a Station. A Track is built up of TrackSections开发者_StackOverflow中文版, which can be regular track sections and electrified tracks sections). A Station is build up of Platforms, which is built up of Tracks which are built up of TrackSections.
So the components(or nodes) I want to connect are the TrackSections, so I want to drag and drop (using right mousebutton) a section onto another section, and this should call a method (command) in my DocumentViewModel (the viewmodel that holds items on the canvas) and not on the sections since the sections doesn't have a clue about other components, nor should they hold the connection.
The goal is to create a list of connections(containing from and to components) which should be able to be rendered ontop of everything as lines, using an adornment layer or similar). I might also add that the components which can be used to create connections all implement a INode interface to be able to identify them.
I hope I described my question and situation clear enough. I can add that I've found plenty of good posts about drag & dropping but I wasn't able to apply any of them to my case, which is why I'm asking here.
Is it right that you want to first place components on the canvas and then create connections between them by dragging from one component to another? What is now your problem with the drag & drop? Why do you think the type of the components is a problem?
I just can guess what you really want but maybe the following approach might work:
- On right click, determine the component and the tracksection your mouse is hovering
- In drag determine if you are hovering another component which allows dropping (give visual cue)
- If dropping allowed, check the tracksection you are hovering
- Create the connection of the tracksections
Here's a link to a Drag&Drop-Framework.
精彩评论