2011-02-10 61 views
0

可拖放控件这就是我要完成的:WPF:水合物帆布在运行时

我想有一个支持拖放和Microsoft Visio中的风格下探任意数据的画布。我发现这个链接是这样的:http://www.codeproject.com/KB/WPF/WPFDiagramDesigner_Part1.aspx

但是,我也想在运行时为画布提供保湿。我发现这篇文章: https://stackoverflow.com/questions/889825/wpf-is-it-possible-to-bind-a-canvass-children-property-in-xaml

其中一个解决方案建议绘制它自己的画布上的每个项目,我已经开始工作。但我无法通过将数据绑定到画布的ItemControl子项来拖放它。理想情况下,我想避免使用代码隐藏来执行此操作。有没有使用我拥有的一切的XAML解决方案?我的代码如下:

这是我创建的MoveThumb,它是实际移动的控件。

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

这是我为每个第一个链接定义的xaml模板。

<ControlTemplate x:Key="MoveThumbTemplate" TargetType="{x:Type t:MoveThumb}"> 
      <Rectangle Fill="Gray"/> 
     </ControlTemplate> 


     <ControlTemplate x:Key="NodeItemTemplate"> 
      <Grid DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}"> 
       <t:MoveThumb Template="{StaticResource MoveThumbTemplate}" 
       Cursor="SizeAll"/> 
       <ContentPresenter Content="{TemplateBinding ContentControl.Content}"/> 
      </Grid> 
     </ControlTemplate> 

     <DataTemplate x:Key="nodeTemplate" DataType="Node">    
       <ContentControl Name="NodeItem" 
           Width="50" 
           Height="50" 
           Canvas.Top="50" 
           Canvas.Left="50" 
           Template="{StaticResource NodeItemTemplate}"> 
        <Ellipse Fill="Black" IsHitTestVisible="False"/> 
       </ContentControl>    
     </DataTemplate> 

这是在画布中创建并绑定我的ItemsControl的xaml。

<ItemsControl ItemsSource="{Binding Path=NodeCollection}" Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> 
       <ItemsControl.ItemsPanel> 
        <ItemsPanelTemplate> 
         <Canvas Background="Yellow" Width="auto" Height="auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" /> 
        </ItemsPanelTemplate> 
       </ItemsControl.ItemsPanel> 
       <ItemsControl.ItemTemplate> 

        <DataTemplate> 
         <ContentControl Name="NodeItem" 
           Width="50" 
           Height="50" 
           Canvas.Top="100" 
           Canvas.Left="100" 
           Template="{StaticResource NodeItemTemplate}"> 
          <Ellipse Fill="Black" IsHitTestVisible="False"/> 
         </ContentControl> 
        </DataTemplate> 

       </ItemsControl.ItemTemplate> 
       <ItemsControl.ItemContainerStyle> 
        <Style> 
         <Setter Property="Canvas.Top" Value="{Binding Path=Y}" /> 
         <Setter Property="Canvas.Left" Value="{Binding Path=X}" /> 
        </Style> 
       </ItemsControl.ItemContainerStyle> 
      </ItemsControl> 

回答

2

我发现,当我在做类似的东西(水平dragable时间轴)的问题是,每一个项目被包裹在一个ContentPresenter它被放置从工作防止拇指在画布上之前。它可以,如果你想要只读显示,但如果你想拖动它成为一个问题。

解决方案是重写GetContainerForItemOverride()方法。我已经包含了我的控制模板,样式和时间轴本身的XAML。
这个链接真的帮了我。 How to change the default item container for ItemsControl?

public class Timeline : ItemsControl 
     { 
      protected override System.Windows.DependencyObject GetContainerForItemOverride() 
      { 
       return new ContentControl(); 
      } 

      protected override void PrepareContainerForItemOverride(System.Windows.DependencyObject element, object item) 
      { 
       var control = element as Control; 
       if (control != null) 
       { 
        var myUri = new Uri("/ResourceDictionary.xaml", UriKind.Relative); 
        var dictionary = Application.LoadComponent(myUri) as ResourceDictionary; 

        if (dictionary != null) 
        { 
         control.Template = (ControlTemplate)dictionary["TimelineElementTemplate"]; 
        } 

        control.DataContext = item; 
       } 
       base.PrepareContainerForItemOverride(element, item); 
      } 
     } 


     <ControlTemplate x:Key="TimelineElementTemplate" TargetType="{x:Type Controls:ContentControl}"> 
       <Grid DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}"> 
        <TextBlock Text="{Binding Path=DataContext.DebugData}"       
           ToolTip="{Binding Path=DataContext.DebugData}" 
           Background="{Binding Path=DataContext.Background}"/> 
        <Control Template="{StaticResource ResizeDecoratorTemplate}" />    
       </Grid> 
      </ControlTemplate> 

    <Style x:Key="TimelineElementStyle" TargetType="Controls:ContentControl"> 
     <Setter Property="Canvas.Left"> 
      <Setter.Value> 
       <Binding Path="LeftPos" Mode="TwoWay"/> 
      </Setter.Value> 
     </Setter> 

     <Setter Property="Width"> 
      <Setter.Value> 
       <Binding Path="Width" Mode="TwoWay"/> 
      </Setter.Value> 
     </Setter>   
    </Style> 

<Style x:Key="TimelineStyle" TargetType="ItemsControl"> 
    <Setter Property="ItemsPanel"> 
     <Setter.Value> 
      <ItemsPanelTemplate> 
       <Canvas Background="LightGray"></Canvas> 
      </ItemsPanelTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 


    <Controls:Timeline Style="{StaticResource TimelineStyle}" 
           DataContext="{StaticResource timelineViewModel}" 
           ItemContainerStyle="{StaticResource TimelineElementStyle}" 
           ItemsSource="{Binding ListOfTimelineElements}" 
           HelperClasses:DragDropHelper.IsDragSource="False" 
           HelperClasses:DragDropHelper.IsDropTarget="True" 
           HelperClasses:SizeObserver.Observe="True"     
           HelperClasses:SizeObserver.ObservedWidth="{Binding TotalWidth, Mode=OneWayToSource}" 
           BorderBrush="Black" 
           BorderThickness="1"> 

      </Controls:Timeline> 
+0

Thanks for this。我也发现了这个可拖动的画布[http://www.codeproject.com/KB/WPF/DraggingElementsInCanvas.aspx],它做了我希望它做的一些事情。我可能会把你的答案和我发现写一些自定义控件的链接结合起来。感谢您的帮助。 – Vish 2011-02-14 18:53:17