2011-02-10 42 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