Drag Drop in WPF is not so complex once you get used to it…. Usually people blog on how to do drag drop with a canvas, I decided to do the drag drop for 2 listboxes since I think it can be more useful to application developers… + a friend, David Silverlight asked me about it so I decided to blog on it
So for our Drag and Drop exercise we will have 2 Listboxes. A “source” listbox and a “destination” listbox, so that the user can grab an item from the source and put it inside the destination listbox… In order to grab the item from the source listbox we need to handle the PreviewMouseLeftButtonDown event so that when the user holds the mouse left button down we can grab the item. Yet as you might be wondering we need to get the actual UI Element that the user selected (and then get the Content value). For this operation I created a helper method which you can see below…
This method will get a UIElement by using hit testing from the point that you specify. Yet if you set a breakpoint and look at the result of the Hit test you will find out that the value that you get from the Hit Test is one of the inner control of the ListBoxItem and not the actual ListBoxItem (for example if you have a TextBlock inside your ItemTemplate of the listbox, you would get the TextBlock). So we need to climb the WPF Visual Tree until we find the ListBoxItem. We are going to do this by trial and error. So we get the UIElement from the Hit Test and pass it to the ItemsContainerGenerator to give us the object source of the ListBoxItem that we are passing. If we do not pass the correct element (i.e if the element that we pass is not the ListBoxItem) the ItemsContainerGenerator will give us back DependencyProperty.UnsetValue, if the return is that we get the Parent from the Visual Tree and try again… Quite simple…
Now that we can get the object value from a point we can grab that value and do the drag drop operation. In order to do this we need to handle the PreviewMouseLeftButtonDown of the “source” listbox as follows
So here we grab the object from the “source” ListBox that we want to put in the “destination” ListBox. Then we call the DoDragDrop and pass the source listbox, the data to send in the DragDrop operation and the DragDrop effects.
Now lets implement the Drop. We have to create an event handler for the Drop event of the “destination” ListBox like the following
So in the event handler of the Drop all we are doing is to get the data that we passed over with the Drag Drop and push it in the Items collection of the “destination” Listbox. It is very important that to remove the Item from the “source” ListBox you use the ItemsSource and not the Items since that would throw an InvalidOperationException because you cannot change the Items collection while doing drag drop operation on the Listbox. Now it is also important to point out that if you remove an item from the ItemsSource but you ItemsSource is not an ObservableCollection(or any other collection that implements the INotifyCollectionChanged interface), nothing will happen i.e the item will not be removed from the source listbox. Basically by changing the ItemsSource we are relying on the DataBinding for the item to be removed…
I created a demo application for this article and also for Part 2 that I will be writing very soon… maybe even tonight Part 2 will be more advanced… It will demo on how one can give a preview of the element while dragging to the other ListBox…
After posting some LINQ posts I decided to return where I really belong, WPF…
So I was wondering on what I should experiment a bit with and I found out that there are not much resources on the Navigation Window. The Navigation window is a really cool component in WPF. Did you ever have a Page and put it as the StartupUri in the App.XAML, if yes definitely you have seen the Navigation window because by default WPF uses the Navigation Window as the parent control, for you to navigate the pages. This does not imply that you can only use the Navigation Window to navigate through the pages, you can also use the Frame control. It is important to state that the navigation work is not done by the Navigation Window, the navigation is done via the NavigationService.
In this post I am not going to talk much about how the navigation service works, I will focus on how one can create a ControlTemplate for the Navigation Window. Lets start by looking at some interesting properties of the Navigation Window. I will only mention 2 of these propertiessince we are only going to use these 2 for our ControlTemplate
- BackStack – Returns a list JournalEntryUri that represent all pages that you have a visited. Unfortunatly the JournalEntryUri is an internal class so you cannot actually cast to this type. Yet since we will use binding we will by pass this problem becuase binding works with reflection so all you need to know is the propeties that you need from this class which are the Name property (which gives you the name of the page in the BackStack) and the Source property which gives you a URI for the page.
- ForwardStack – Returns a list of JornalEntryUri that represent all pages that you have returned from by using the Back command or the NavigateJournal.
Commands (for more info on commands visit this post)
This command does not take any parameters. All you have to do is execute it or in case you are using a button (or any other controls that have the Command property) set the Command property to the NavigationCommands.BrowseBack. The Can Execute of this command will return true only if you have a page in the BackStack.
Basically this command is the the same as the BrowseBack command but it takes the navigation forward instead of backwards
This command is used to navigate to a specific page. As a parameter this command takes a FrameworkElement that as DataContext has a JournalEntry. Yes quites strange but this is usually what you will have at hand when trying to execute the command (we will look at this later on)
Ok, so now that we are armed with some commands and properties that we can use let’s go ahead and start building our own template for a Navigation Window that has bread crumbs
Lets start off by creating a basic control template with a back and forward button…
Ok, so what we created here is basically a control template for a Navigation Window that has 2 buttons for Back and Forward. Please note that I have a ContentPresenter that has the name of PART_NavWinCP. This is very important because the Navigation Window will look for a ContentPresenter of that name in order to show the pages inside it. Another important thing that we did in the code above is to set the NavigationCommands.BrowseBack to the Command property of the back button and the same for the forward button.
Now let us create our beloved bread crumbs…
I choose to use an ItemsControl for the bread crumbs. The ItemsSource for the ItemsControl is the BackStack property of the Navigation Window since this list has all the JournalEntries. I then forced the ItemsContol to use a WrapPanel as an Items host. The important part is the DataTemplate that I am creating. Basically I a creating a button that as Commands executes the NavigationCommands.NavigateJournal command. I am passing this command the Button object itself since this button object has the journal entry as data context (the data context for the button is “set” by the data template).
As you can see it is relativly easy to create a Control Template for a Navigation Window…. I created a nicer Control Template for the Navigation Window that you can go ahead and download…
P.S There is a problem with this. The problem is that the BackStack will give you the pages in the opposite order that you would want them so the bread crumbs would look like this
Page3 >> Page2 >> Page1
instead of this
Page1 >> Page2 >> Page3
I created my own WrapPanel so that it inverts the elements… All I had to do is open Reflector disassemble the code and change the order of the ArrangeOverride… You can find this in the download… Any questions please contant me – email@example.com
Have loads of WPF fun….