2010-08-18 53 views
4

我想实现使用WPF和画布的捕捉网格。我想我的数学已经关闭了,因为UIElement不会在后台捕捉到网格。下面是我用来创建网格的xaml以及我用来尝试将UIElement对齐到最近的网格线的方法。一旦鼠标按钮事件被触发,所使用的方法就会被触发。如果这不是WPF的正确方法,是否有人能指引我朝着正确的方向发展?实现WPF捕捉网格

XAML

<Border x:Name="dragBorder" 
      BorderBrush="Black" 
      BorderThickness="1" 
      Margin="5" 
      CornerRadius="3"> 
     <Canvas x:Name="dragCanvas" 
          AllowDragging="true" 
          AllowDragOutOfView="False" 
          Height="{Binding ElementName=dragBorder, Path=ActualHeight}" 
          Width="{Binding ElementName=dragBorder, Path=ActualWidth}"> 
      <Canvas.Background> 
       <VisualBrush TileMode="Tile" 
          Viewport="0,0,16,16" 
          ViewportUnits="Absolute" 
          Viewbox="0,0,16,16" 
          ViewboxUnits="Absolute"> 
        <VisualBrush.Visual> 
         <Ellipse Fill="#FF000000" 
           Width="2" 
           Height="2" /> 
        </VisualBrush.Visual> 
       </VisualBrush> 
      </Canvas.Background> 
     </Canvas> 
    </Border> 

方法

private void SnapToGrid(UIElement element) 
    { 
     double xSnap = (Canvas.GetLeft(element)/gridWidth) * gridWidth; 
     double ySnap = (Canvas.GetTop(element)/gridWidth) * gridWidth; 

     Canvas.SetLeft(element, xSnap); 
     Canvas.SetTop(element, ySnap); 

     double tempX = Canvas.GetLeft(element); 
     double tempY = Canvas.GetTop(element); 
    } 

回答

7

你的问题是你的功能实际上并没有做任何事情。除以网格大小,然后乘以网格大小,所以实际上你什么都不做(2 * 16/16 = 2)。您需要使用的是模数%操作员,并根据距网格大小的距离调整x/y位置。

这里是卡左/上工作的功能,如果靠近左/顶格线或右/另有下来:

private void SnapToGrid(UIElement element) { 
    double xSnap = Canvas.GetLeft(element) % GRID_SIZE; 
    double ySnap = Canvas.GetTop(element) % GRID_SIZE; 

    // If it's less than half the grid size, snap left/up 
    // (by subtracting the remainder), 
    // otherwise move it the remaining distance of the grid size right/down 
    // (by adding the remaining distance to the next grid point). 
    if(xSnap <= GRID_SIZE/2.0) 
     xSnap *= -1; 
    else 
     xSnap = GRID_SIZE - xSnap; 
    if(ySnap <= GRID_SIZE/2.0) 
     ySnap *= -1; 
    else 
     ySnap = GRID_SIZE - ySnap; 

    xSnap += Canvas.GetLeft(element); 
    ySnap += Canvas.GetTop(element); 

    Canvas.SetLeft(element, xSnap); 
    Canvas.SetTop(element, ySnap); 
} 
1

Canvas.GetLeft(element)将返回了一倍,所以即使gridWidth是会做双重算术的整数,除法和乘法会或多或少抵消。我想你想要做的其中之一:

double xSnap = Math.Floor(Canvas.GetLeft(element)/gridWidth) * gridWidth; 
double xSnap = Math.Ceiling(Canvas.GetLeft(element)/gridWidth) * gridWidth; 
double xSnap = Math.Round(Canvas.GetLeft(element)/gridWidth) * gridWidth; 

那些将四舍五入的结果划分为一个整数,并返回一个gridWidth的倍数。

0

这样做是为了确保任何物体的位置被限制为一定数量的;即最终位置应该是圆形的并落在该组内。

该集合包含任意数字的所有因子,j; j控制“快照”的强度并确定哪些数字出现在集合中。新的位置也必须只包含出现在集合中的数字。

例如,说一个对象的原始位置是(5, 0),我们希望将它移动到(16, 23)。让我们继续并快速给出:这意味着对象的位置可能只包含因子。原来的位置已经落在这个集合中,但是新的位置却没有。

为了模拟“贴紧”,新位置必须落在(15,20)(20, 25)之上。寻找最近的因子和,会给你正确的一点。在大多数情况下,有必要对结果进行四舍五入。

//Get original point of object relative to container element 
var original_point = e.GetPosition(sender); 

//Calculate new x and y position based on mouse 
//var new_x = ... 
//var new_y = ... 

//New position must be multiple of 8  
var snap = 8; 

//Get nearest factor of result position 
new_x = original_point.X.NearestFactor(snap); 
new_y = original_point.Y.NearestFactor(snap); 

public static double NearestFactor(this double Value, double Factor) 
{ 
    return Math.Round((Value/Factor), MidpointRounding.AwayFromZero) * Factor; 
} 

不言而喻,这种算法可以调整的对象时,也可以使用,以确保这两个对象的位置和大小“抓拍”。