2011-10-15 42 views

回答

4

我没有见过任何像这样的控制,我想你必须自己编写它。 这里有几件事情要实现,我只会谈论图表部分。 首先,你应该定义一个关于这个控件应该如何表现的清单(即,只有在鼠标按钮关闭时用光标移动线条),然后完成......好吧,这是有趣的部分!

编辑:好的,现在这里是一个粗糙的版本,当我说粗糙时,我的意思是。我把它放在一个窗口而不是用户控件中,你可以将它粘贴到你的控件中。这有许多缺陷,只有在解决所有问题后才能有效使用。另外,将像素设计与灵活/相对设计(如拉伸对齐)混合时,您必须小心。我通过使窗口不可调整大小来限制它的像素精度。

<Window x:Class="graphedit.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="MainWindow" 
    x:Name="window" 
    MouseMove="Window_MouseMove" 
    Height="400" Width="400" 
    ResizeMode="NoResize"> 
<Canvas x:Name="canvas" 
     HorizontalAlignment="Stretch" 
     VerticalAlignment="Stretch"> 
    <Canvas.Background> 
     <RadialGradientBrush> 
      <GradientStop Color="#333333" Offset="1"></GradientStop> 
      <GradientStop Color="#666666" Offset="0"></GradientStop> 
     </RadialGradientBrush> 
    </Canvas.Background> 
    <Border BorderThickness="0,0,1,1" 
      BorderBrush="White" 
      Margin="0,0,0,0" 
      Width="{Binding Path=Point.X}" 
      Height="{Binding Path=Point.Y}"></Border> 

    <Border BorderThickness="1,1,0,0" 
      BorderBrush="White" 
      Margin="{Binding Path=BottomRightBoxMargin}" 
      Width="{Binding Path=BottomRightBoxDimensions.X}" 
      Height="{Binding Path=BottomRightBoxDimensions.Y}"></Border> 
    <Border BorderThickness="1" 
      BorderBrush="White" 
      Margin="{Binding Path=GripperMargin}" 
      Background="DimGray" 
      CornerRadius="4"    
      Width="10" 
      x:Name="gripper" 
      MouseDown="gripper_MouseDown" 
      MouseUp="gripper_MouseUp" 
      Height="10"></Border> 
    <TextBox Text="{Binding Path=Point.X}" Canvas.Left="174" Canvas.Top="333" Width="42"></TextBox> 
    <TextBox Text="{Binding Path=Point.Y}" Canvas.Left="232" Canvas.Top="333" Width="45"></TextBox> 
    <TextBlock Foreground="White" Canvas.Left="162" Canvas.Top="336">X</TextBlock> 
    <TextBlock Canvas.Left="222" Canvas.Top="336" Foreground="White" Width="13">Y</TextBlock> 
</Canvas> 

代码隐藏看起来如下:

using System.ComponentModel; 
using System.Windows; 

namespace graphedit 
{ 
/// <summary> 
/// Interaction logic for MainWindow.xaml 
/// </summary> 
public partial class MainWindow : Window, INotifyPropertyChanged 
{ 
    private bool isDragging; 

    private Point mousePositionBeforeMove; 

    private Point point; 

    public Point Point 
    { 
     get { return this.point; } 
     set 
     { 
      this.point = value; 
      this.InvokePropertyChanged(null); 
     } 
    } 

    public Thickness BottomRightBoxMargin 
    { 
     get 
     { 
      Thickness t = new Thickness() 
          { 
           Left = this.Point.X, 
           Top = this.Point.Y 
          }; 
      return t; 
     } 
    } 

    public Thickness GripperMargin 
    { 
     get 
     { 
      Thickness t = new Thickness() 
      { 
       Left = this.Point.X - 5, 
       Top = this.Point.Y - 5 
      }; 
      return t; 
     } 
    } 

    public Point BottomRightBoxDimensions 
    { 
     get 
     { 
      return new Point(this.Width - this.Point.X, 
          this.Height - this.Point.Y); 
     } 
    } 

    public MainWindow() 
    { 
     InitializeComponent(); 
     this.Point = new Point(100, 80); 
     this.DataContext = this; 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    public void InvokePropertyChanged(string name) 
    { 
     PropertyChangedEventArgs args = new PropertyChangedEventArgs(name); 
     PropertyChangedEventHandler handler = this.PropertyChanged; 
     if (handler != null) 
     { 
      handler(this, args); 
     } 
    } 

    private void gripper_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e) 
    { 
     this.isDragging = true; 
     this.mousePositionBeforeMove = e.GetPosition(this.canvas); 
    } 

    private void gripper_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e) 
    { 
     this.isDragging = false; 
    } 

    private void Window_MouseMove(object sender, System.Windows.Input.MouseEventArgs e) 
    { 
     if(this.isDragging) 
     { 
      Point currentMousePosition = e.GetPosition(this.canvas); 
      double deltaX = currentMousePosition.X - this.mousePositionBeforeMove.X; 
      double deltaY = currentMousePosition.Y - this.mousePositionBeforeMove.Y; 

      double newPointX = (this.Point.X + deltaX < 0 ? 0 : (this.Point.X + deltaX > this.Width ? this.Width : this.Point.X + deltaX)) ; 
      double newPointY = (this.Point.Y + deltaY < 0 ? 0 : (this.Point.Y + deltaY > this.Width ? this.Width : this.Point.Y + deltaY)) ; 

      this.Point = new Point(newPointX,newPointY); 
      this.mousePositionBeforeMove = currentMousePosition; 
     } 
    } 
} 
} 
1

你可以看看图表库DynamicDataDisplay。这是一个由微软(afaik)作为研究项目创建的库,可能提供您正在寻找的功能。

首先,引用DynamicDataDisplay DLL在您的项目,然后在XAML创建以下的命名空间:

xmlns:d3="http://research.microsoft.com/DynamicDataDisplay/1.0" 

然后,你可以一个ChartPlotter对象添加到XAML剥夺你不从它需要的一切(轴,图例,...)。您可以使用CursorCoordinateGraph来跟踪鼠标。如果你想改变布局等,你可以使用一个VerticalRange对象。

<d3:ChartPlotter Width="500" Height="300" 
        MainHorizontalAxisVisibility="Collapsed" 
        MainVerticalAxisVisibility="Collapsed" 
        LegendVisibility="Collapsed" NewLegendVisible="False"> 
     <!--This allows you to track the mouse-->  
     <d3:CursorCoordinateGraph x:Name="cursorGraph"/> 
     <!-- this range does nothing more then make the background gray, 
      there are other ways to achieve this too--> 
     <d3:VerticalRange Value1="-300" Value2="300" Fill="Gray"/> 
    </d3:ChartPlotter> 

如果你想跟踪鼠标的位置,您可以使用代码隐藏:

Point current = cursorGraph.Position; 

Position属性绑定到您的视图模型:

<d3:CursorCoordinateGraph x:Name="cursorGraph" Position="{Binding CurrentMousePosition}"/> 

如果你想在点击时真正修复位置,我想你必须在OnClick或MouseClick事件处理程序中为ChartPlotter和c创建一个新的CursorCoordinateGraph alculate点并提供新的图:

//pseudo code!!! 
mainGraph.DoubleClick += HandleDoubleClick; 

private void HandleDoubleClick(object sender, MouseButtonEventArgs e){ 
    //get position from current graph: 
    var position = cursor.Position; 
    //you have to calculate the "real" position in the chart because 
    //the Point provided by Position is not the real point, but screen coordinates 
    //something like cursor.TranslatePoint(cursor.Position, mainGraph); 
    var newCoord = new CursorCoordinateGraph { Position = position }; 
    mainGraph.Children.Add(newCoord); 
} 

你可能有一些工作,使其看起来像你想。我建议您浏览codeplex页面上提供的示例并查看讨论页面。这个库很大,有很多可能性,但是提供的实际文档很少......

希望这点能指引您朝着正确的方向发展!

1

我制作了简单的可重用ControllerCanvas控件的演示。希望它能帮助你。您可以在您的XAML中设置所有属性。

ControllerCanvas.cs

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Input; 
using System.Windows.Media; 

namespace XYControllerDemo 
{ 
    public class ControllerCanvas : Canvas 
    { 
     #region Dependency Properties 

     public Point Point 
     { 
      get { return (Point)GetValue(PointProperty); } 
      set 
      { 
       if (value.X < 0.0) 
       { 
        value.X = 0.0; 
       } 

       if (value.Y < 0.0) 
       { 
        value.Y = 0.0; 
       } 

       if (value.X > this.ActualWidth) 
       { 
        value.X = this.ActualWidth; 
       } 

       if (value.Y > this.ActualHeight) 
       { 
        value.Y = this.ActualHeight; 
       } 

       SetValue(PointProperty, value); 
      } 
     } 

     public static readonly DependencyProperty PointProperty = 
      DependencyProperty.Register("Point", typeof(Point), typeof(ControllerCanvas), new FrameworkPropertyMetadata(new Point(), 
       FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender)); 

     public Brush ControllerStroke 
     { 
      get { return (Brush)GetValue(ControllerStrokeProperty); } 
      set { SetValue(ControllerStrokeProperty, value); } 
     } 

     public static readonly DependencyProperty ControllerStrokeProperty = 
      DependencyProperty.Register("ControllerStroke", typeof(Brush), typeof(ControllerCanvas), new FrameworkPropertyMetadata(Brushes.Red, 
       FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender)); 

     public double ControllerStrokeThickness 
     { 
      get { return (double)GetValue(ControllerStrokeThicknessProperty); } 
      set { SetValue(ControllerStrokeThicknessProperty, value); } 
     } 

     public static readonly DependencyProperty ControllerStrokeThicknessProperty = 
      DependencyProperty.Register("ControllerStrokeThickness", typeof(double), typeof(ControllerCanvas), new FrameworkPropertyMetadata(1.0, 
       FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender)); 

     public Brush GridStroke 
     { 
      get { return (Brush)GetValue(GridStrokeProperty); } 
      set { SetValue(GridStrokeProperty, value); } 
     } 

     public static readonly DependencyProperty GridStrokeProperty = 
      DependencyProperty.Register("GridStroke", typeof(Brush), typeof(ControllerCanvas), new FrameworkPropertyMetadata(Brushes.LightGray, 
       FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender)); 

     public double GridStrokeThickness 
     { 
      get { return (double)GetValue(GridStrokeThicknessProperty); } 
      set { SetValue(GridStrokeThicknessProperty, value); } 
     } 

     public static readonly DependencyProperty GridStrokeThicknessProperty = 
      DependencyProperty.Register("GridStrokeThickness", typeof(double), typeof(ControllerCanvas), new FrameworkPropertyMetadata(1.0, 
       FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender)); 

     public bool GridVisible 
     { 
      get { return (bool)GetValue(GridVisibleProperty); } 
      set { SetValue(GridVisibleProperty, value); } 
     } 

     public static readonly DependencyProperty GridVisibleProperty = 
      DependencyProperty.Register("GridVisible", typeof(bool), typeof(ControllerCanvas), new FrameworkPropertyMetadata(false, 
       FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender)); 

     public Thickness GridMargin 
     { 
      get { return (Thickness)GetValue(GridMarginProperty); } 
      set { SetValue(GridMarginProperty, value); } 
     } 

     public static readonly DependencyProperty GridMarginProperty = 
      DependencyProperty.Register("GridMargin", typeof(Thickness), typeof(ControllerCanvas), new FrameworkPropertyMetadata(new Thickness(0.0, 0.0, 0.0, 0.0), 
       FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender)); 

     public double GridSize 
     { 
      get { return (double)GetValue(GridSizeProperty); } 
      set { SetValue(GridSizeProperty, value); } 
     } 

     public static readonly DependencyProperty GridSizeProperty = 
      DependencyProperty.Register("GridSize", typeof(double), typeof(ControllerCanvas), new FrameworkPropertyMetadata(30.0, 
       FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender)); 

     #endregion 

     #region Drawing Context 

     Pen penGrid = null; 
     Pen penController = null; 

     Brush previousGridStroke = null; 
     double previousGridStrokeThickness = double.NaN; 
     double penGridHalfThickness = double.NaN; 

     Brush previousControllerStroke = null; 
     double previousControllerStrokeThickness = double.NaN; 
     double penControllerHalfThickness = double.NaN; 

     Point p1 = new Point(); 
     Point p2 = new Point(); 
     Point p3 = new Point(); 
     Point p4 = new Point(); 

     double width = double.NaN; 
     double height = double.NaN; 

     void DrawGrid(DrawingContext dc) 
     { 
      width = this.ActualWidth; 
      height = this.ActualHeight; 

      // draw vertical grid lines 
      for (double y = GridMargin.Top; y <= height - GridMargin.Bottom; y += GridSize) 
      { 
       p1.X = GridMargin.Left; 
       p1.Y = y; 
       p2.X = width - GridMargin.Right; 
       p2.Y = y; 

       GuidelineSet g = new GuidelineSet(); 
       g.GuidelinesX.Add(p1.X + penGridHalfThickness); 
       g.GuidelinesX.Add(p2.X + penGridHalfThickness); 
       g.GuidelinesY.Add(p1.Y + penGridHalfThickness); 
       g.GuidelinesY.Add(p2.Y + penGridHalfThickness); 
       dc.PushGuidelineSet(g); 
       dc.DrawLine(penGrid, p1, p2); 
       dc.Pop(); 
      } 

      // draw horizontal grid lines 
      for (double x = GridMargin.Left; x <= width - GridMargin.Right; x += GridSize) 
      { 
       p1.X = x; 
       p1.Y = GridMargin.Top; 
       p2.X = x; 
       p2.Y = height - GridMargin.Bottom; 

       GuidelineSet g = new GuidelineSet(); 
       g.GuidelinesX.Add(p1.X + penGridHalfThickness); 
       g.GuidelinesX.Add(p2.X + penGridHalfThickness); 
       g.GuidelinesY.Add(p1.Y + penGridHalfThickness); 
       g.GuidelinesY.Add(p2.Y + penGridHalfThickness); 
       dc.PushGuidelineSet(g); 
       dc.DrawLine(penGrid, p1, p2); 
       dc.Pop(); 
      } 
     } 

     void DrawController(DrawingContext dc) 
     { 
      width = this.ActualWidth; 
      height = this.ActualHeight; 

      // draw vertical controller line 
      p1.X = 0.0; 
      p1.Y = Point.Y; 
      p2.X = width; 
      p2.Y = Point.Y; 

      GuidelineSet g1 = new GuidelineSet(); 
      g1.GuidelinesX.Add(p1.X + penControllerHalfThickness); 
      g1.GuidelinesX.Add(p2.X + penControllerHalfThickness); 
      g1.GuidelinesY.Add(p1.Y + penControllerHalfThickness); 
      g1.GuidelinesY.Add(p2.Y + penControllerHalfThickness); 
      dc.PushGuidelineSet(g1); 
      dc.DrawLine(penController, p1, p2); 
      dc.Pop(); 

      // draw horizontal controller line 
      p3.X = Point.X; 
      p3.Y = 0.0; 
      p4.X = Point.X; 
      p4.Y = height; 

      GuidelineSet g2 = new GuidelineSet(); 
      g2.GuidelinesX.Add(p3.X + penControllerHalfThickness); 
      g2.GuidelinesX.Add(p4.X + penControllerHalfThickness); 
      g2.GuidelinesY.Add(p3.Y + penControllerHalfThickness); 
      g2.GuidelinesY.Add(p4.Y + penControllerHalfThickness); 
      dc.PushGuidelineSet(g2); 
      dc.DrawLine(penController, p3, p4); 
      dc.Pop(); 
     } 

     protected override void OnRender(DrawingContext dc) 
     { 
      base.OnRender(dc); 

      // create ord update grid pen 
      if (penGrid == null) 
      { 
       penGrid = new Pen(GridStroke, GridStrokeThickness); 

       previousGridStroke = GridStroke; 
       previousGridStrokeThickness = GridStrokeThickness; 

       penGridHalfThickness = penGrid.Thickness/2.0; 
      } 
      else 
      { 
       if (GridStroke != previousGridStroke || GridStrokeThickness != previousGridStrokeThickness) 
       { 
        previousGridStroke = GridStroke; 
        previousGridStrokeThickness = GridStrokeThickness; 
        penGrid.Brush = GridStroke; 
        penGrid.Thickness = GridStrokeThickness; 

        penGridHalfThickness = penGrid.Thickness/2.0; 
       } 
      } 

      // create ord update controller pen 
      if (penController == null) 
      { 
       penController = new Pen(ControllerStroke, ControllerStrokeThickness); 

       previousControllerStroke = ControllerStroke; 
       previousControllerStrokeThickness = ControllerStrokeThickness; 

       penControllerHalfThickness = penController.Thickness/2.0; 
      } 
      else 
      { 
       if (ControllerStroke != previousControllerStroke || ControllerStrokeThickness != previousControllerStrokeThickness) 
       { 
        previousControllerStroke = ControllerStroke; 
        previousControllerStrokeThickness = ControllerStrokeThickness; 
        penController.Brush = ControllerStroke; 
        penController.Thickness = ControllerStrokeThickness; 

        penControllerHalfThickness = penController.Thickness/2.0; 
       } 
      } 

      // drag grid 
      if (GridVisible) 
      { 
       DrawGrid(dc); 
      } 

      // draw controller 
      DrawController(dc); 
     } 

     #endregion 

     #region Mouse Events 

     protected override void OnMouseLeftButtonDown(System.Windows.Input.MouseButtonEventArgs e) 
     { 
      if (!this.IsMouseCaptured) 
      { 
       this.Point = e.GetPosition(this); 

       this.Cursor = Cursors.Hand; 
       this.CaptureMouse(); 
      } 

      base.OnMouseLeftButtonDown(e); 
     } 

     protected override void OnMouseLeftButtonUp(System.Windows.Input.MouseButtonEventArgs e) 
     { 
      if (this.IsMouseCaptured) 
      { 
       this.Cursor = Cursors.Arrow; 
       this.ReleaseMouseCapture(); 
      } 

      base.OnMouseLeftButtonUp(e); 
     } 

     protected override void OnMouseMove(System.Windows.Input.MouseEventArgs e) 
     { 
      if (this.IsMouseCaptured) 
      { 
       this.Point = e.GetPosition(this); 
      } 

      base.OnMouseMove(e); 
     } 

     #endregion 
    } 
} 

MainWindow.xaml

<Window x:Class="XYControllerDemo.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:local="clr-namespace:XYControllerDemo" 
     Title="XYControllerDemo" Height="410" Width="680"> 
    <Grid> 

     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="50*"/> 
      <ColumnDefinition Width="50*"/> 
     </Grid.ColumnDefinitions> 

     <Grid.RowDefinitions> 
      <RowDefinition Height="Auto"/> 
      <RowDefinition Height="Auto"/> 
     </Grid.RowDefinitions> 

     <local:ControllerCanvas x:Name="controller1" 
           Margin="10" Grid.Column="0" Grid.Row="0" 
           Background="Transparent" Width="300" Height="300" 
           GridMargin="0,0,0,0" GridVisible="True" GridSize="30" 
           GridStroke="LightGray" GridStrokeThickness="1.0" 
           ControllerStroke="Red" ControllerStrokeThickness="1.0" 
           Point="50,50"/> 

     <TextBox Grid.Row="1" Grid.Column="0" Margin="10" Width="100" 
       Text="{Binding ElementName=controller1, Path=Point, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> 

     <local:ControllerCanvas x:Name="controller2" 
           Margin="10" Grid.Column="1" Grid.Row="0" 
           Background="Transparent" Width="300" Height="300" 
           GridMargin="0,0,0,0" GridVisible="True" GridSize="30" 
           GridStroke="LightGray" GridStrokeThickness="1.0" 
           ControllerStroke="Blue" ControllerStrokeThickness="1.0" 
           Point="90,250"/> 

     <TextBox Grid.Row="1" Grid.Column="1" Margin="10" Width="100" 
       Text="{Binding ElementName=controller2, Path=Point, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> 

    </Grid> 
</Window> 

MainWindow.xaml.cs

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Data; 
using System.Windows.Documents; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Imaging; 
using System.Windows.Navigation; 
using System.Windows.Shapes; 

namespace XYControllerDemo 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 
     } 
    } 
} 
相关问题