The MouseDragElementBehavior
acts upon the FrameworkElement
you attach it to. In your case it is the Border
element which will be contained by a ContentPresenter
which is the container generated by the ItemsControl
. You have set ConstrainToParentBounds="True"
which will ensure the visual will not be displayed outside its container, in this case the ContentPresenter
. There are a few options, some easy, one probably not worth undertaking (but I did to figure some stuff out).
- Set
ConstrainToParentBounds="False"
. I am supposing that you don't want the Border
to leave the ItemsControl
so this probably won't suit.
- Set the
ItemContainerStyle
to a Style
which sets the Template
to and adds the interaction to a similarly configured ContentPresenter
. The base implementation of the ItemsControl
uses a vanilla ContentPresenter
. A caveat here is that if you aren't using UI elements as items you will need to wrap the item in one using a custom items control (see this answer on setting the container style):
<ItemsControl Grid.Column="1" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<ContentPresenter>
<i:Interaction.Behaviors>
<ei:MouseDragElementBehavior ConstrainToParentBounds="True"/>
</i:Interaction.Behaviors>
</ContentPresenter>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style >
</ItemsControl.ItemContainerStyle>
<ItemsControl.Items>
Test item
</ItemsControl.Items>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Width="20" Height="20">
<Rectangle Fill="Red"/>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
- Attach the interaction using the
ItemsControl.ItemContainerStyle
. This is a little involved because the Interaction.Behaviors
attached property only has a setter:
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="beh:AddCollectionsToSetter.Behaviors">
<Setter.Value>
<beh:BehaviorCollection>
<ei:MouseDragElementBehavior ConstrainToParentBounds="True"/>
</beh:BehaviorCollection>
</Setter.Value>
</Setter>
</Style>
</ItemsControl.ItemContainerStyle>
For this I had to create a separate attached property AddCollectionsToSetter.Behaviors
which is read/write and a BehaviorCollection
that allows the interactions to be added to.
public static class AddCollectionsToSetter
{
#region Behaviors Dependency Property (Attached)
/// <summary>Gets the behaviours to add.</summary>
public static BehaviorCollection GetBehaviors(DependencyObject obj)
{
return (BehaviorCollection)obj.GetValue(BehaviorsProperty);
}
/// <summary>Sets the behaviours to add.</summary>
public static void SetBehaviors(DependencyObject obj, BehaviorCollection value)
{
obj.SetValue(AddCollectionsToSetter.BehaviorsProperty, value);
}
/// <summary>DependencyProperty backing store for <see cref="Behaviors"/>. Represents the behaviours to add.</summary>
/// <remarks></remarks>
public static readonly DependencyProperty BehaviorsProperty =
DependencyProperty.RegisterAttached("Behaviors", typeof(BehaviorCollection), typeof(AddCollectionsToSetter), new PropertyMetadata(null, BehaviorsPropertyChanged));
private static void BehaviorsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var oldBehaviors = (BehaviorCollection)e.OldValue;
var newBehaviors = (BehaviorCollection)e.NewValue;
var interaction = Interaction.GetBehaviors(d);
interaction.RemoveRange(oldBehaviors); // extension method, simple iterate and remove
interaction.AddRange(newBehaviors.Clone()); // extension method, simple iterate and add
}
#endregion Behaviors Dependency Property (Attached)
}
public class BehaviorCollection : FreezableCollection<System.Windows.Interactivity.Behavior>
{
public BehaviorCollection()
: base()
{
}
public BehaviorCollection(int capacity)
: base(capacity)
{
}
public BehaviorCollection(IEnumerable<System.Windows.Interactivity.Behavior> behaviors)
: base(behaviors)
{
}
}