2010-08-18 54 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; 
} 

不言而喻,這種算法可以調整的對象時,也可以使用,以確保這兩個對象的位置和大小「抓拍」。