简体   繁体   中英

How to properly set the DataContext of DataTemplate Controls

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; }
    }
}

I have not tried it out, but http://www.codeproject.com/Articles/22952/WPF-Diagram-Designer-Part seems likely to have the answer for you.

Edit: I see from the comments that the problem is with moving from Canvas to ItemsControl . It seems there is a problem with Canvas.Top and Canvas.Left in that context, and a solution setting some styles properties: Dragable objects in WPF in an ItemsControl?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM