This is a follow on from this question: Items added to ItemsControl not using ItemTemplate
I have 2 classes that should handle moving and resizing of objects (MoveThumb
and ResizeThumb
). The templates are being applied to objects in an ItemsControl
and the functions that should transform the objects are being fired but I am unable to get it to work.
The ItemsControl
is bound to an ObservableCollection
of 'DashboardItems' which at the moment are just simple objects that return an X and Y for Canvas.SetTop/Left
. I'll probably be adding to them in the future but I want to get the basics working first
In the comparison in MoveThumb_DragDelta
'item' is always null. ResizeThumb
has the same problem.
Sender is a MoveThumb
and sender.DataContext
is a ContentPresenter
My question is: How should I properly set up the data contexts of the templates and/or classes so that MoveThumb_DragDelta
can get the Control that fired it?
EDIT:
Changing Control item = this.DataContext as Control;
to UIElement item = this.DataContext as UIElement;
has got the movement working but resizing is not working as UIElement does not contain ActualHeight/Width or MinHeight/Width.
MoveThumb
:
public class MoveThumb : Thumb
{
public MoveThumb()
{
DragDelta += new DragDeltaEventHandler(this.MoveThumb_DragDelta);
}
private void MoveThumb_DragDelta(object sender, DragDeltaEventArgs e)
{
Control item = this.DataContext as Control;
if (item != null)
{
double left = Canvas.GetLeft(item);
double top = Canvas.GetTop(item);
Canvas.SetLeft(item, left + e.HorizontalChange);
Canvas.SetTop(item, top + e.VerticalChange);
}
}
}
MainWindow.xaml
:
<Window.Resources>
<ControlTemplate x:Key="MoveThumbTemplate" TargetType="{x:Type local:MoveThumb}">
<Rectangle Fill="Transparent"/>
</ControlTemplate>
<ControlTemplate x:Key="ResizeDecoratorTemplate" TargetType="Control">
<Grid>
<local:ResizeThumb Height="2" Cursor="SizeNS" Margin="0 -4 0 0" VerticalAlignment="Top" HorizontalAlignment="Stretch"/>
<local:ResizeThumb Width="2" Cursor="SizeWE" Margin="-4 0 0 0" VerticalAlignment="Stretch" HorizontalAlignment="Left"/>
<local:ResizeThumb Width="2" Cursor="SizeWE" Margin="0 0 -4 0" VerticalAlignment="Stretch" HorizontalAlignment="Right"/>
<local:ResizeThumb Height="2" Cursor="SizeNS" Margin="0 0 0 -4" VerticalAlignment="Bottom" HorizontalAlignment="Stretch"/>
<local:ResizeThumb Width="7" Height="7" Cursor="SizeNWSE" Margin="-6 -6 0 0" VerticalAlignment="Top" HorizontalAlignment="Left"/>
<local:ResizeThumb Width="7" Height="7" Cursor="SizeNESW" Margin="0 -6 -6 0" VerticalAlignment="Top" HorizontalAlignment="Right"/>
<local:ResizeThumb Width="7" Height="7" Cursor="SizeNESW" Margin="-6 0 0 -6" VerticalAlignment="Bottom" HorizontalAlignment="Left"/>
<local:ResizeThumb Width="7" Height="7" Cursor="SizeNWSE" Margin="0 0 -6 -6" VerticalAlignment="Bottom" HorizontalAlignment="Right"/>
</Grid>
</ControlTemplate>
<DataTemplate DataType="{x:Type local:TableControl}">
<Grid DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}">
<local:MoveThumb Template="{StaticResource MoveThumbTemplate}" DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}" Cursor="SizeAll"/>
<Control Template="{StaticResource ResizeDecoratorTemplate}"/>
<Button Content="x" VerticalAlignment="Top" HorizontalAlignment="Right" Width="10" Height="10" Click="Button_Click"/>
<Ellipse Fill="Red" IsHitTestVisible="False" Height="100" Width="100"/>
</Grid>
</DataTemplate>
<DataTemplate DataType="{x:Type local:GraphControl}">
<Grid DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}">
<local:MoveThumb Template="{StaticResource MoveThumbTemplate}" DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}" Cursor="SizeAll"/>
<Control Template="{StaticResource ResizeDecoratorTemplate}"/>
<Button Content="x" VerticalAlignment="Top" HorizontalAlignment="Right" Width="10" Height="10" Click="Button_Click"/>
<Ellipse Fill="Green" IsHitTestVisible="False" Height="100" Width="100"/>
</Grid>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ribbon:Ribbon Margin="0,-22,0,0" Grid.Row="0">
<ribbon:RibbonTab Header="Dashboard">
<ribbon:RibbonGroup Header="Customise">
<ribbon:RibbonMenuButton Label="New" FontSize="20" Height="60" Width="60">
<ribbon:RibbonMenuItem Header="Graph" Click="NewGraph"/>
<ribbon:RibbonMenuItem Header="Table" Click="NewTable"/>
</ribbon:RibbonMenuButton>
</ribbon:RibbonGroup>
</ribbon:RibbonTab>
</ribbon:Ribbon>
<ItemsControl Name="dashboardControls" ItemsSource="{Binding Path=CanvasContents}" Grid.Row="1">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Canvas.Top" Value="{Binding Path=Y}"/>
<Setter Property="Canvas.Left" Value="{Binding Path=X}"/>
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
</Grid>
MainWindow.xaml.cs
:
public partial class MainWindow : Window
{
public static Dashboard dashboard;
public MainWindow()
{
dashboard = new Dashboard();
InitializeComponent();
this.DataContext = dashboard;
}
private void NewGraph(object sender, RoutedEventArgs e)
{
dashboard.CanvasContents.Add(new GraphControl());
}
private void NewTable(object sender, RoutedEventArgs e)
{
dashboard.CanvasContents.Add(new TableControl());
}
}
Dashboard.cs
:
public class Dashboard: INotifyPropertyChanged
{
ObservableCollection<DashboardItem> _canvasContents;
public Dashboard()
{
_canvasContents = new ObservableCollection<DashboardItem>();
}
public ObservableCollection<DashboardItem> CanvasContents
{
get { return _canvasContents; }
}
}
DashboardItem.cs
:
public abstract class DashboardItem
{
public int X
{
get { return 100; }
}
public int Y
{
get { return 100; }
}
}