さまざまな種類の線を描画できる描画アプリケーションを開発しています。ライン コーナー ポイントに、itemsControl を使用して親指を配置しました。ユーザーがマウスを左クリックしてマウスをドラッグすると、親指はそのコーナーポイントを移動する必要があります。これを行うと、ポイントと親指が少し動きますが、すぐにマウスのキャプチャが失われ、もう動きません。正しく起動された最初の dragdelta イベントをデバッグすると、送信サムから itemscontrol までの完全なビジュアル ツリーが追跡されますが、次に起動すると、サムの位置が更新されず、コンテンツ プレゼンターが含まれている場合があります。ビジュアル ツリーに null の親があります。
これは、行のサム ポイントに関連する xaml の一部です。
<ItemsControl x:Name="PART_LineRelocate" ItemsSource="{Binding pointsObservableCollection}" Visibility="Collapsed" >
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type s:LineCornerPoint}" >
<Grid>
<c:PointRelocateThumb VerticalAlignment="Center" HorizontalAlignment="Center" Focusable="True" x:Name="PART_PointRelocateThumb" Cursor="Hand"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas IsItemsHost="True" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle >
<Style >
<Style.Triggers>
<DataTrigger Value="BrokenLinkLine" Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type s:ToolLine}}, Path=indicator}" >
<Setter Property="Canvas.Left" Value="{Binding Corner.X}" />
<Setter Property="Canvas.Top" Value="{Binding Corner.Y}" />
</DataTrigger>
....More of these datatriggers for the different types of lines
</Style.Triggers>
</Style>
</ItemsControl.ItemContainerStyle>
PointRelocateThumb のコード:
public PointRelocateThumb()
{
base.DragDelta += new DragDeltaEventHandler(this.PointRelocateThumb_DragDelta);
}
void PointRelocateThumb_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
{
PointRelocateThumb prt = (PointRelocateThumb)sender;
LineCornerPoint lcp = (LineCornerPoint)prt.DataContext;
Point thumbPoint = new Point(Canvas.GetLeft((ContentPresenter)prt.TemplatedParent), Canvas.GetTop((ContentPresenter)prt.TemplatedParent));
ToolLine toolLine = null;
DrawingCanvas designer = null;
ItemsControl itemsControl = ItemsControl.ItemsControlFromItemContainer(prt.TemplatedParent);
if (itemsControl != null)
toolLine = itemsControl.DataContext as ToolLine;
if (toolLine != null)
designer = VisualTreeHelper.GetParent(toolLine) as DrawingCanvas;
if (toolLine != null && designer != null && toolLine.IsSelected)
{
thumbPoint = new Point(thumbPoint.X + Canvas.GetLeft(toolLine) + 3.5, thumbPoint.Y + Canvas.GetTop(toolLine) + 3.5);
toolLine.undoBounding();
if (System.String.Compare(toolLine.indicator, "BrokenLinkLine") == 0
|| System.String.Compare(toolLine.indicator, "LinkLine") == 0
|| System.String.Compare(toolLine.indicator, "OrthogonalLinkLine") == 0
|| System.String.Compare(toolLine.indicator, "BrokenLine") == 0
|| System.String.Compare(toolLine.indicator, "Line") == 0
|| System.String.Compare(toolLine.indicator, "Polygon") == 0)
{
if (toolLine.pathFigure.StartPoint.Equals(thumbPoint))
{
toolLine.pathFigure.StartPoint = new Point(modifyingToolLine.pathFigure.StartPoint.X + e.HorizontalChange, modifyingToolLine.pathFigure.StartPoint.Y + e.VerticalChange); }
else
{
foreach (LineSegment ls in toolLine.pathSegmentCollection)
{
if (ls.Point.Equals(thumbPoint))
{
ls.Point = new Point(ls.Point.X + e.HorizontalChange, ls.Point.Y + e.VerticalChange);
break;
}
}
}
}
toolLine.regenerateBoundingItem();
}
e.Handled = true;
}
}
}
Tooline はライン クラスです。undo バインディングが行うことは、toolLine の Canvas.Left と Canvas.Top が 0 に設定されるようにすることですが、同じポイントに位置するようにポイントをスケーリングします。つまり、古い Canvas.Left と Canvas を追加します。ライン内の各ポイントへの toolLine の上位値。
境界項目を再生成するためのコードは次のとおりです。
public void regenerateBoundingItem()
{
//Following line of code just regenerates the underlying path for the toolLine from the
//new pathsegmentCollection and pathFigure start point.
regenerateThisLine();
double leftMostPoint = double.MaxValue, topMostPoint = double.MaxValue, bottomMostPoint = double.MinValue, rightMostPoint = double.MinValue;
getBoundingPoints(ref leftMostPoint, ref topMostPoint, ref bottomMostPoint, ref rightMostPoint);
//subtracts leftMost point and topMostPoint from each point in the line
scaleLinePoints(leftMostPoint, topMostPoint);
Canvas.SetLeft(this, leftMostPoint);
Canvas.SetTop(this, topMostPoint);
this.Width = rightMostPoint - leftMostPoint;
this.Height = bottomMostPoint-topMostPoint;
regenerateObservableCollection();
regenerateThisLine();
}
private void regenerateObservableCollection()
{
if (this.pointsObservableCollection == null)
this.pointsObservableCollection = new ObservableCollection<LineCornerPoint>();
this.pointsObservableCollection.Clear();
LineCornerPoint startPt = new LineCornerPoint(new Point(this.pathFigure.StartPoint.X - 3.5, this.pathFigure.StartPoint.Y - 3.5));
this.pointsObservableCollection.Add(startPt);
if (System.String.Compare(indicator, "BrokenLine") == 0
|| System.String.Compare(indicator, "BrokenLinkLine") == 0
|| System.String.Compare(indicator, "LinkLine") == 0
|| System.String.Compare(indicator, "Polygon") == 0
|| System.String.Compare(indicator, "Line") == 0)
{
foreach (LineSegment ls in pathSegmentCollection)
{
LineCornerPoint pt = new LineCornerPoint(new Point(ls.Point.X - 3.5, ls.Point.Y - 3.5));
this.pointsObservableCollection.Add(pt);
}
}
}
PointRelocateThumb のテンプレートは、幅と高さが 7 の楕円です。これが、すべてのつまみの位置を 3.5 オフセットしなければならない理由を説明しています。