我有一个 ScrollViewer,里面有一些扩展器,扩展器的内容有一个画布。我在 Canvas 上绘制了两个矩形,它们是可以拖动的 Thumb 控件。问题是,每当我按下矩形并尝试拖动时,它都会以某种方式假定我想滚动整个页面并且拖动永远不会发生。如何在 ScrollViewer 中解决此问题。
我在 MSDN for UWP 上看到了一个名为的属性CanBeScrollAnchor
,它说该属性用于(获取或设置一个值,该值指示 UIElement 是否可以成为滚动锚定的候选对象。)。但是将其设置为 false 并没有帮助。(我添加 WPF 标记是因为概念相同)。请帮忙
编辑:此问题仅发生在触摸屏上。
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Hidden">
<StackPanel Orientation="Vertical" HorizontalAlignment="Stretch">
<uwpControls:Expander>
<!--Some Content-->
</uwpControls:Expander>
<uwpControls:Expander HeaderStyle="{StaticResource ToggleButtonFullWidthHeader}"
Background="{StaticResource ListViewItemBackgroundBrush}" Margin="0,20,0,0" HorizontalAlignment="Stretch" Header="DragDrop">
<Grid x:Name="gridBarImagePanel" Grid.Row="4" BorderBrush="Black" BorderThickness="2">
<uwpControls:ImageEx x:Name="BarCodeImage" IsCacheEnabled="True" Source="..\SampleImage\demo.png"
Stretch="UniformToFill" />
<Canvas x:Name="cnvBarCodeImage" Canvas.ZIndex="100" VerticalAlignment="Stretch">
</Canvas>
</Grid>
</uwpControls:Expander>
</StackPanel>
</ScrollViewer>
在后面的代码中,我调用此方法在 Canvas 上动态绘制两个 Thumb 控件。
public sealed partial class SomeControl:Page
{
event Action<Thumb, double, double> ChangeDimensions;
public void OnSomeButtonClick(object sender,EventArgs e)
{
//TEST(Remove this)
dimensions.Add(new Dimensions()
{
Height = 80,
Width = 150,
left = 250,
Top = 40,
BorderColor = BrushCollection[0],
MaxLeftPossible = null,
MaxTopPossible = null,//280
MaxRightPossible = null,
MaxBottomPossible = null,
});
dimensions.Add(new Dimensions()
{
Height = 80,
Width = 150,
left = 250,
Top = 150,
BorderColor = BrushCollection[1],
MaxLeftPossible = null,
MaxTopPossible = null,//280
MaxRightPossible = null,
MaxBottomPossible = null,
});
//CreateUIShapes(SelectedRowItem.WindowLocations.Count, dimensions);
CreateUIShapes(2, dimensions);
}
private void CreateUIShapes(int numberOfWindows, List<Dimensions> dimensions)
{
Thumb th = null;
for (int i = 0; i < numberOfWindows; i++)
{
th = new Thumb();
th.Name = string.Format("{0}{1}", "Thumb", i + 1);
var item = dimensions[i];
th.Width = item.Width;
th.Height = item.Height;
th.Foreground = new SolidColorBrush(Windows.UI.Colors.Transparent);
th.BorderBrush = item.BorderColor;
th.BorderThickness = new Thickness(3);
th.DragDelta += (sender, e) => Th_DragDelta(sender, e, dimensions);
th.DragCompleted += (sender, e) => Th_DragCompleted(sender, e);
Canvas.SetLeft(th, CheckAndGetItemToLeft(item.left, i));
Canvas.SetTop(th, CheckAndGetItemTotop(item.Top, i));
cnvBarCodeImage.Children.Add(th);
}
}
//This is the code to drag and drop.
private void Th_DragDelta(object sender, DragDeltaEventArgs e, List<Dimensions> LimitedWindowMovements)
{
var SelectedDraggableThumb = sender as Thumb;
double left = (Canvas.GetLeft(SelectedDraggableThumb) >= 0) ? Canvas.GetLeft(SelectedDraggableThumb) : 0;
double top = (Canvas.GetTop(SelectedDraggableThumb) >= 0) ? Canvas.GetTop(SelectedDraggableThumb) : 0;
if (ChkDualMode.IsChecked == true)
{
var OtherDraggableThumbs = cnvBarCodeImage.Children.OfType<Thumb>().Where(x => x != SelectedDraggableThumb);
var maxTopSelected = LimitedWindowMovements[0].MaxTopPossible == null ? 1 : LimitedWindowMovements[0].MaxTopPossible;
var maxBottomSelected = LimitedWindowMovements[0].MaxBottomPossible == null ? BarCodeImage.ActualHeight - SelectedDraggableThumb.ActualHeight : LimitedWindowMovements[0].MaxBottomPossible;
var maxLeftSelected = LimitedWindowMovements[0].MaxLeftPossible == null ? 0 : LimitedWindowMovements[0].MaxLeftPossible;
var maxRightSelected = LimitedWindowMovements[0].MaxRightPossible == null ? BarCodeImage.ActualWidth - SelectedDraggableThumb.Width : LimitedWindowMovements[0].MaxRightPossible;
//Boundry case for top->Current element.
//Don't allow further up.
if (top < maxTopSelected) //Hardcoding for now. top < 1 original.
{
if (e.VerticalChange <= 1)
{
ChangeDimensions -= BarCodeServiceView_ChangeDimensions;
return;
}
}
//Boundry case for bottom->Current element.
//Don't allow further down.
//Canvas.GetTop(SelectedDraggableThumb) >= BarCodeImage.ActualHeight - SelectedDraggableThumb.ActualHeight original.
else if (Canvas.GetTop(SelectedDraggableThumb) >= maxBottomSelected)
{
if (e.VerticalChange > 0)
{
ChangeDimensions -= BarCodeServiceView_ChangeDimensions;
return;
}
}
//Boundry case for left->Current element.
//Don't allow further left.
//Canvas.GetLeft(SelectedDraggableThumb) <= 0 original.
else if (Canvas.GetLeft(SelectedDraggableThumb) <= maxLeftSelected)
{
if (e.HorizontalChange <= 1)
{
ChangeDimensions -= BarCodeServiceView_ChangeDimensions;
return;
}
}
//Boundry case for left->Current element.
//Don't allow further right.
//Math.Round(Canvas.GetLeft(SelectedDraggableThumb), 1) >= BarCodeImage.ActualWidth - SelectedDraggableThumb.Width original.
else if (Math.Round(Canvas.GetLeft(SelectedDraggableThumb), 1) >= maxRightSelected)
{
if (e.HorizontalChange >= 0)
{
ChangeDimensions -= BarCodeServiceView_ChangeDimensions;
return;
}
}
//There may be n number of windows.
foreach (var item in OtherDraggableThumbs)
{
//Boundry case for the other thumb moving up.
//Don't allow further up.
//var OtherTop = Canvas.GetTop(item); original
var OtherTop = Canvas.GetTop(item);
if (OtherTop < maxTopSelected)
{
if (e.VerticalChange <= 1)
{
ChangeDimensions -= BarCodeServiceView_ChangeDimensions;
return;
}
}
//Boundry case for the other thumb moving bottom
//Don't allow further bottom.
//BarCodeImage.ActualHeight - SelectedDraggableThumb.ActualHeight original
if (Canvas.GetTop(item) >= maxBottomSelected)
{
if (e.VerticalChange > 0)
{
ChangeDimensions -= BarCodeServiceView_ChangeDimensions;
return;
}
}
//Boundry case for the other thumb moving left.
//Don't allow further left
//Canvas.GetLeft(item) <= 0 original
if (Canvas.GetLeft(item) <= maxLeftSelected)
{
if (e.HorizontalChange <= 1)
{
ChangeDimensions -= BarCodeServiceView_ChangeDimensions;
return;
}
}
//Boundry case for the other thumb moving right.
//Don't allow further right
//Math.Round(Canvas.GetLeft(item), 1) >= BarCodeImage.ActualWidth - item.Width original
if (Math.Round(Canvas.GetLeft(item), 1) >= maxRightSelected)
{
if (e.HorizontalChange >= 0)
{
ChangeDimensions -= BarCodeServiceView_ChangeDimensions;
return;
}
}
if (ChangeDimensions == null)
{
ChangeDimensions += BarCodeServiceView_ChangeDimensions;
}
}
foreach (var item in OtherDraggableThumbs)
{
ChangeDimensions?.Invoke(item, e.HorizontalChange, e.VerticalChange);
}
}
left = (Canvas.GetLeft(SelectedDraggableThumb) > BarCodeImage.ActualWidth - SelectedDraggableThumb.ActualWidth) ? BarCodeImage.ActualWidth - SelectedDraggableThumb.ActualWidth : left;
top = (Canvas.GetTop(SelectedDraggableThumb) > BarCodeImage.ActualHeight - SelectedDraggableThumb.ActualHeight) ? BarCodeImage.ActualHeight - SelectedDraggableThumb.ActualHeight : top;
Canvas.SetLeft(SelectedDraggableThumb, left + e.HorizontalChange);
Canvas.SetTop(SelectedDraggableThumb, top + e.VerticalChange);
}
//When one thumb moves, I want to move the other in the same direction.
private void BarCodeServiceView_ChangeDimensions(Thumb sender, double arg1, double arg2)
{
if (sender != null)
{
//4025e8df
double left = (Canvas.GetLeft(sender) > 0) ? Canvas.GetLeft(sender) : 0;
double top = (Canvas.GetTop(sender) > 0) ? Canvas.GetTop(sender) : 0;
left = (Canvas.GetLeft(sender) > BarCodeImage.ActualWidth - sender.ActualWidth) ? BarCodeImage.ActualWidth - sender.ActualWidth : left;
top = (Canvas.GetTop(sender) > BarCodeImage.ActualHeight - sender.ActualHeight) ? BarCodeImage.ActualHeight - sender.ActualHeight : top;
Canvas.SetLeft(sender, left + arg1);
Canvas.SetTop(sender, top + arg2);
}
}
private void Th_DragCompleted(object sender, DragCompletedEventArgs e)
{
//Do something.
foreach (var item in cnvBarCodeImage.Children.OfType<Thumb>())
{
ChangeDimensions -= BarCodeServiceView_ChangeDimensions;
}
}
}
public class Dimensions
{
public double Height { get; set; }
public double Width { get; set; }
public double left { get; set; }
public double Top { get; set; }
public Windows.UI.Xaml.Media.Brush BorderColor { get; set; }
/// <summary>
/// If no restriction needed specify null
/// </summary>
public double? MaxTopPossible { get; set; }
/// <summary>
/// If no restriction needed specify null
/// </summary>
public double? MaxLeftPossible { get; set; }
/// <summary>
/// If no restriction needed specify null
/// </summary>
public double? MaxRightPossible { get; set; }
/// <summary>
/// If no restriction needed specify null
/// </summary>
public double? MaxBottomPossible { get; set; }
}