The libraries goes open source!

Up from now all the libraries are available open source.
Please find the links if you click on the “Source” below the library.

http://github.com/DavidWCSL
http://github.com/DavidWCSL/Dianthus
http://github.com/DavidWCSL/Galantus
http://github.com/DavidWCSL/Lilium
http://github.com/DavidWCSL/Tulipa

I appreciate any feedback in my guestbook :)

David W.

Simple item drag and drop between two bound lists.

I would like to show how easy in WPF items can be drag and drop between two bound lists in both directions.
The example shows the easiest way without any adorner effects currently.

First of all we start with two list boxed besides, the code is very easy therefore I think I can show it without additional comments.

The user object which is shown in both list and which will be dragged

public class User : INotifyPropertyChanged
{
    public User(string name)
    {
        Name = name;
    }
 
    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            OnPropertyChanged("Name");
        }
    }
    private string _name;
 
    public override string ToString()
    {
        return Name;
    }
 
    #region PropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string property)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(property));
        }
    }
    #endregion PropertyChanged
}

A simply factory for creating some users

public class UserFactory
{
    public static List<User> CreateUsers()
    {
        return new List<User>
        {
            new User("Willy"),
            new User("Jeff"),
            new User("Vanessa"),
            new User("Chris"),
            new User("Michael"),
            new User("Steve"),
            new User("David")
        };
    }
}

The main window which display both Lists

<Window x:Class="DragAndDropDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"
        Height="350" MinHeight="350"
        Width="525" MinWidth="525">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
 
        <ListBox ItemsSource="{Binding AvailableUsers}" />
 
        <ListBox Grid.Column="1" ItemsSource="{Binding ChoosenUsers}" />
 
    </Grid>
</Window>

And the code for creating the lists

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;
 
        AvailableUsers = new EnhancedObservableCollection<User>();
        ChoosenUsers = new EnhancedObservableCollection<User>();
 
        CreateUsers();
    }
 
    private void CreateUsers()
    {
        AvailableUsers.AddRange(UserFactory.CreateUsers());
    }
 
    public EnhancedObservableCollection<User> AvailableUsers { get; set; }
 
    public EnhancedObservableCollection<User> ChoosenUsers { get; set; }
}

(The EnhancedObservableCollection is a control in Tulipa which provides AddRange, RemoveAll, RemoveRange and Sort)

The target now is to have the possibility to drag the user from the “AvailableUsers” to the “ChoosenUsers” and back.
Dragging with other data except the users object will not allowed.

First we have to starting a dragging, for this we take the PreviewMouseLeftButtonDown and the PreviewMouseMove

In the PreviewMouseLeftButtonDown we define that the user would like to start a drag and drop. And in the PreviewMouseMove we check if a dragging should start and do it.
It is possible to start the drag and drop in the PreviewMouseLeftButtonDown directly, but then the ListBoxes will have problems with the normal selection.
The events in both lists use the same event handler in the code.

The events taken

PreviewMouseLeftButtonDown="Available_PreviewMouseLeftButtonDown"
PreviewMouseMove="Available_PreviewMouseMove"

After pressing on an item the e.OriginalSource should be the element which display the bound object, in my example it’s a TextBlock, there the object is located in the DataContext.
This object will be remembered and the owner of the object too, this is necessary to prevent an dropping in the source list.
private object _dragData;
private object _senderList;

private void Available_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    FrameworkElement element = e.OriginalSource as FrameworkElement;
    if (element != null &&
        element.DataContext != null)
    {
        _dragData = element.DataContext;
        _senderList = sender;
    }
}

if the mouse is moved over the control, it checks if a dragging action is requested and start the DoDragDrop with the provided object.
The object is reset as soon the DoDragDrop is done.

private void Available_PreviewMouseMove(object sender, MouseEventArgs e)
{
    if (_dragData != null)
    {
        DragDrop.DoDragDrop((DependencyObject)sender, _dragData, DragDropEffects.Move);
        _dragData = null;
    }
}

If we build and test this we see that now we can drag an item, but we have no possible target control, therefore the mouse cursor every time is this “forbidden” icon.

Lets define targets for the items, to allow dropping into the lists the controls need the property AllowDrop enabled
As soon this is set to true the controls will trigger the drag events.
If we let this as is all items can be dropped now, we we won’t that, therefore we take the PreviewDragEnter and PreviewDragOver on both lists.
In the event handler we clarify if the current drag action is allowed on the control or not.

The events taken

PreviewDragEnter="Choosen_PreviewDragEnterOver"
PreviewDragOver="Choosen_PreviewDragEnterOver"

Because only “User” should be possible to drop from one side to another we forbid the action if the data is not a user object and if the mouse is over the source list.
For forbidding or allowing the dragging action we simply have to define the Effects property.

private void Choosen_PreviewDragEnterOver(object sender, DragEventArgs e)
{
    User draggedUser = GetDataUser(e.Data);
    if (draggedUser != null &&
        sender != _senderList)
    {
        e.Effects = DragDropEffects.All;
    }
    else
    {
        e.Effects = DragDropEffects.None;
    }
    e.Handled = true;
}
 
private User GetDataUser(IDataObject dataObject)
{
    return dataObject.GetData(typeof(User)) as User;
}

The drag over event normally is enough, but the mouse short flicker on dragging into another control if drag enter isn’t handled.
The event handler have to set Handled on the end otherwise the framework will set all files on allowed and the given Effects will be ignored.

And now the last step, dropping the object from one list to another.
For this we have to take the PreviewDrop on both lists. In the event handler we take the data, check from which list it comes from and move it to the other list.

The event taken

PreviewDrop="Choosen_PreviewDrop"

In the event handler the data is taken and moved from one list to another.

private void Choosen_PreviewDrop(object sender, DragEventArgs e)
{
    User draggedUser = GetDataUser(e.Data);
    if (draggedUser != null)
    {
        if (AvailableUsers.Contains(draggedUser))
        {
            MoveUser(draggedUser, AvailableUsers, ChoosenUsers);
        }
        else
        {
            MoveUser(draggedUser, ChoosenUsers, AvailableUsers);
        }
    }
}
 
private void MoveUser(User user, EnhancedObservableCollection<User> source, EnhancedObservableCollection<User> target)
{
    source.Remove(user);
    target.Add(user);
}

Lets see all together

<Window x:Class="DragAndDropDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"
        Height="350" MinHeight="350"
        Width="525" MinWidth="525">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
 
        <ListBox ItemsSource="{Binding AvailableUsers}"
                 AllowDrop="True"
                 PreviewMouseLeftButtonDown="Available_PreviewMouseLeftButtonDown"
                 PreviewMouseMove="Available_PreviewMouseMove"
                 PreviewDragEnter="Choosen_PreviewDragEnterOver"
                 PreviewDragOver="Choosen_PreviewDragEnterOver"
                 PreviewDrop="Choosen_PreviewDrop" />
 
        <ListBox Grid.Column="1"
                 ItemsSource="{Binding ChoosenUsers}"
                 AllowDrop="True"
                 PreviewMouseLeftButtonDown="Available_PreviewMouseLeftButtonDown"
                 PreviewMouseMove="Available_PreviewMouseMove"
                 PreviewDragEnter="Choosen_PreviewDragEnterOver"
                 PreviewDragOver="Choosen_PreviewDragEnterOver"
                 PreviewDrop="Choosen_PreviewDrop" />
 
    </Grid>
</Window>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;
 
        AvailableUsers = new EnhancedObservableCollection<User>();
        ChoosenUsers = new EnhancedObservableCollection<User>();
 
        CreateUsers();
    }
 
    private void CreateUsers()
    {
        AvailableUsers.AddRange(UserFactory.CreateUsers());
    }
 
    public EnhancedObservableCollection<User> AvailableUsers { get; set; }
    public EnhancedObservableCollection<User> ChoosenUsers { get; set; }
 
    private object _dragData;
    private object _senderList;
    private void Available_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        FrameworkElement element = e.OriginalSource as FrameworkElement;
        if (element != null &&
            element.DataContext != null)
        {
            _dragData = element.DataContext;
            _senderList = sender;
        }
    }
 
    private void Available_PreviewMouseMove(object sender, MouseEventArgs e)
    {
        if (_dragData != null)
        {
            DragDrop.DoDragDrop((DependencyObject)sender, _dragData, DragDropEffects.Move);
            _dragData = null;
        }
    }
 
    private void Choosen_PreviewDragEnterOver(object sender, DragEventArgs e)
    {
        User draggedUser = GetDataUser(e.Data);
        if (draggedUser != null &&
            sender != _senderList)
        {
            e.Effects = DragDropEffects.All;
        }
        else
        {
            e.Effects = DragDropEffects.None;
        }
        e.Handled = true;
    }
 
    private User GetDataUser(IDataObject dataObject)
    {
        return dataObject.GetData(typeof(User)) as User;
    }
 
    private void Choosen_PreviewDrop(object sender, DragEventArgs e)
    {
        User draggedUser = GetDataUser(e.Data);
        if (draggedUser != null)
        {
            if (AvailableUsers.Contains(draggedUser))
            {
                MoveUser(draggedUser, AvailableUsers, ChoosenUsers);
            }
            else
            {
                MoveUser(draggedUser, ChoosenUsers, AvailableUsers);
            }
        }
    }
 
    private void MoveUser(User user, EnhancedObservableCollection<User> source, EnhancedObservableCollection<User> target)
    {
        source.Remove(user);
        target.Add(user);
    }
}

Like I wrote before, this is the easiest way without any better visual feedback for the user and without the possibility to define where exactly the items should be inserted in the target list.

Have fun with it.

David W.

Dianthus 4 now released

I’m glad to tell that Dianthus now retrieve a release state :) some controls are still missing, but the important controls are available.
Please see the preview page for some screenshots, and download the library in the downloads page.
To start using it please take a look in the Window description in the documentation :)

Have fun with it.

David W.

Feedback or questions?

I now have a guestbook available, there you can wrote what you like in English or German :) Any kind of feedback or questions are welcome :)
Please find the guestbook on top of the page.

David W.

I’m still alive :)

We can see my last posting is nearly one month ago, but this doesn’t mean that I’m sleeping ;)
I’m currently working on Dianthus v4.0, the main focus in this version is, like in Tulipa, the possibility to overwrite the templates and an easy to use.

For the main controls like the window, tab items, application menu and quick launch bar I’m nearly done already, in a 2007 and 2010 silver version.

Please be patience :)

David W.

Welcome: Galantus

WPF has the really great benefit to have the possibility to change every style and template. Every control and window can be redesigned to looks like a new control.
In my opinion its bad that this is not possible everywhere, I’m speak about the standard dialog which every application needs, the dialogs for open or save files and so on.
Therefore I have started a new library called Galantus.
This library currently capsulate the Forms dialog into a WPF window, just for starting.
The usage now is like every other WPF window without any benefit. I start to implement each control by myself with the target to have these dialogs prepared to be style able and no needed Forms or Drawing references anymore.
The Dialogs currently are: OpenFileDialog, SaveFileDialog, BrowseFolderDialog, ColorPickerDialog and FontPickerDialog.

I’m looking forward for the first dialogs. I’m starting with the BrowseFolderDialog.

David W.

Support for DW.* stopped now

Up from now the old controls DW.Controls, DW.Ribbons and DW.MVVMLib are not supported anymore.
If you use one of them, please upgrade to Tulipa, Dianthus and Lilium.

David W.

Visual Studio, Common Properties

Its a small change but it might be usefully for some developers.
The properties for each control now is in the Common properties area in Visual Studio at design time.

Its available in Tulipa 4.0.21.0

David W.

And more improvements for the EllipsedProgressBar

Today I again have used my EllipsedProgressBar and found one issue and have get some ideas.
- If the control was started in the Visibility.Collapsed state and enables later on, it was not rotating, this I have fixed
- The speed now is changeable by defining the Speed property
- IsEnabled now is supported, the control then stops in the starting position
- The IsEnabled, Color, Speed, Visibility and Size now can be changed at runtime

Everything is available in Tulipa version 4.0.20.0

David W.

Do you like a better EllipsedProgressBar?

I have planned to implement a new EllipsedProgressBar with more possibilities like an wide ellipse or display of a real process.
Because I have no time to create a new one I just have enhanced the current EllipsedProgressBar.
That are the changes in detail:
- The EllipsedProgressBar internally uses the EllipsePanel, this panel was throwing an exception if the size is below then 0, that I have changed so the EllipsedProgressBar will not crash anymore if the size is 0.
- The EllipsedProgressBar now can be set to Visibility.Collapsed.
- The EllipsedProgressBar now can rotate in both directions, see the Direction property.
- The EllipsedProgressBar now every time will be a square, that means if the height is not the same as the width, the width will be taken. That means it is enough to set the Width property of the control, the height will be adjusted automatically.

Everything is available in Tulipa version 4.0.15.0.

David W.