views:

201

answers:

2

Hello,

I'm trying to host the Workflow Designer in a WPF application. The WorkflowView control is hosted under a WindowsFormsHost control. I've managed to load workflows onto the designer which is successfully linked to a PropertyGrid, also hosted in another WindowsFormsHost.

WorkflowView workflowView = rootDesigner.GetView(ViewTechnology.Default) as WorkflowView;
window.WorkflowViewHost.Child = workflowView;

The majority of the rehosting code is the same as in http://msdn.microsoft.com/en-us/library/aa480213.aspx.

I've created a custom Toolbox using a ListBox WPF control bound to a list of ToolboxItems.

<ListBox Grid.Row="1" Margin="0 0 0 4" BorderThickness="1" BorderBrush="DarkGray" ItemsSource="{Binding Path=ToolboxItems}" PreviewMouseLeftButtonDown="ListBox_PreviewMouseLeftButtonDown" AllowDrop="True">
 <ListBox.Resources>
  <vw:BitmapSourceTypeConverter x:Key="BitmapSourceConverter" />
 </ListBox.Resources>
 <ListBox.ItemTemplate>
  <DataTemplate DataType="{x:Type dd:ToolboxItem}">
   <StackPanel Orientation="Horizontal" Margin="3">
    <Image Source="{Binding Path=Bitmap, Converter={StaticResource BitmapSourceConverter}}" Height="16" Width="16" Margin="0 0 3 0"     />
    <TextBlock Text="{Binding Path=DisplayName}" FontSize="14" Height="16" VerticalAlignment="Center" />
    <StackPanel.ToolTip>
     <TextBlock Text="{Binding Path=Description}" />
    </StackPanel.ToolTip>
   </StackPanel>
  </DataTemplate>
 </ListBox.ItemTemplate>
</ListBox>

In the ListBox_PreviewMouseLeftButtonDown handler:

private void ListBox_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
 ListBox parent = (ListBox)sender;

 UIElement dataContainer;
 //get the ToolboxItem for the selected item
 object data = GetObjectDataFromPoint(parent, e.GetPosition(parent), out dataContainer);

 //if the data is not null then start the drag drop operation
 if (data != null)
 {
  DataObject dataObject = new DataObject();
  dataObject.SetData(typeof(ToolboxItem), data);

  DragDrop.DoDragDrop(parent, dataObject, DragDropEffects.Move | DragDropEffects.Copy);
 }
}

With that setup, I'm unable to drag any item from my custom Toolbox onto the designer. The cursor is always displayed as "No" anywhere on the designer.

I've been trying to find anything about this on the net for half a day now and I really hope some can help me here.

Any feedback is much appreciated. Thank you!

Carlos

A: 

This might sound stupid as my system is shutting down. :) But can you check your WorkflowView for whether AllowDrop is set? Have you handled the DragEnter event?

mqbt
Yes, I've checked AllowDrop both in the WindowsFormsHost and WorkflowView controls and they're both set to true. I've also handled the DragEvent and the e.Data argument field contains the System.Windows.Forms.DataObject equivalent of the System.Windows.DataObject I made before calling DragDrop.DoDragDrop. I was able to get the ToolboxItem from e.Data just fine.
ca7l0s
A: 

Finally got Drag and Drop working. There were three things that needed doing, for whatever reason WorkflowView has:

1.) I had to use System.Windows.Forms.DataObject instead of System.Windows.DataObject when serializing the ToolboxItem when doing DragDrop.

private void ListBox_MouseDownHandler(object sender, MouseButtonEventArgs e)
{
    ListBox parent = (ListBox)sender;

    //get the object source for the selected item
    object data = GetObjectDataFromPoint(parent, e.GetPosition(parent));

    //if the data is not null then start the drag drop operation
    if (data != null)
    {
     System.Windows.Forms.DataObject dataObject = new System.Windows.Forms.DataObject();
     dataObject.SetData(typeof(ToolboxItem), data as ToolboxItem);
     DragDrop.DoDragDrop(this, dataObject, DragDropEffects.Move | DragDropEffects.Copy);
    }
}

2.) DragDrop.DoDragDrop source must be set to the IToolboxService set in the IDesignerHost. The control holding the ListBox implements IToolboxService.

// "this" points to ListBox's parent which implements IToolboxService.
DragDrop.DoDragDrop(this, dataObject, DragDropEffects.Move | DragDropEffects.Copy);

3.) The ListBox should be bound to a list of ToolboxItems returned by the following helper method, passing it the Type of the activities to show in the tool box:

...
this.ToolboxItems = new ToolboxItem[] 
    {
     GetToolboxItem(typeof(IfElseActivity))
    };
...

internal static ToolboxItem GetToolboxItem(Type toolType)
{
    if (toolType == null)
     throw new ArgumentNullException("toolType");

    ToolboxItem item = null;
    if ((toolType.IsPublic || toolType.IsNestedPublic) && typeof(IComponent).IsAssignableFrom(toolType) && !toolType.IsAbstract)
    {
     ToolboxItemAttribute toolboxItemAttribute = (ToolboxItemAttribute)TypeDescriptor.GetAttributes(toolType)[typeof(ToolboxItemAttribute)];
     if (toolboxItemAttribute != null && !toolboxItemAttribute.IsDefaultAttribute())
     {
      Type itemType = toolboxItemAttribute.ToolboxItemType;
      if (itemType != null)
      {
       // First, try to find a constructor with Type as a parameter.  If that
       // fails, try the default constructor.
       ConstructorInfo ctor = itemType.GetConstructor(new Type[] { typeof(Type) });
       if (ctor != null)
       {
        item = (ToolboxItem)ctor.Invoke(new object[] { toolType });
       }
       else
       {
        ctor = itemType.GetConstructor(new Type[0]);
        if (ctor != null)
        {
         item = (ToolboxItem)ctor.Invoke(new object[0]);
         item.Initialize(toolType);
        }
       }
      }
     }
     else if (!toolboxItemAttribute.Equals(ToolboxItemAttribute.None))
     {
      item = new ToolboxItem(toolType);
     }
    }
    else if (typeof(ToolboxItem).IsAssignableFrom(toolType))
    {
     // if the type *is* a toolboxitem, just create it..
     //
     try
     {
      item = (ToolboxItem)Activator.CreateInstance(toolType, true);
     }
     catch
     {
     }
    }

    return item;
}

GetToolboxItem method is from http://msdn.microsoft.com/en-us/library/aa480213.aspx source, in the ToolboxService class.

Cheers, Carlos

ca7l0s