oxyplot 点击x,y交汇的点,标签一直显示

文章描述了一个在前端图形库中实现自定义触摸事件绑定和追踪器行为的示例。通过TouchPlotGrid组件,设置了BindToMouseDown属性以响应左侧鼠标点击,并使用ShowTrackerAndLeaveOpenBehavior类来控制追踪器的行为,包括在鼠标按下时显示并保持追踪器打开。代码中还包括了后台如何设置这一行为以及相关的事件处理和控制器操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       前端:

<local:TouchPlot Grid.Row="1" x:Name="pv" local:ShowTrackerAndLeaveOpenBehavior.BindToMouseDown="Left" Margin="0,0,5,0"  />

如果你是后台写,就这样:

 TouchPlot plt = new TouchPlot { Model = GetPlot() };//GetPlot()是自定义方法
 ShowTrackerAndLeaveOpenBehavior.SetBindToMouseDown(plt, OxyMouseButton.Left);


 自定义的类

public class TouchPlot : PlotView
    {
        protected override void OnTouchDown(TouchEventArgs e)
        {
            var args = new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left);
            args.RoutedEvent = PreviewMouseLeftButtonDownEvent;
            args.Source = e.OriginalSource;
            RaiseEvent(args);
            e.Handled = true;
        }
    }

public static class ShowTrackerAndLeaveOpenBehavior
    {
        public static readonly DependencyProperty BindToMouseDownProperty = DependencyProperty.RegisterAttached(
            "BindToMouseDown", typeof(OxyMouseButton), typeof(ShowTrackerAndLeaveOpenBehavior),
            new PropertyMetadata(default(OxyMouseButton), OnBindToMouseButtonChanged));

        [AttachedPropertyBrowsableForType(typeof(IPlotView))]
        public static void SetBindToMouseDown(DependencyObject element, OxyMouseButton value) =>
            element.SetValue(BindToMouseDownProperty, value);

        [AttachedPropertyBrowsableForType(typeof(IPlotView))]
        public static OxyMouseButton GetBindToMouseDown(DependencyObject element) =>
            (OxyMouseButton)element.GetValue(BindToMouseDownProperty);

        private static void OnBindToMouseButtonChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (!(d is IPlotView plot))
                throw new InvalidOperationException($"Can only be applied to {nameof(IPlotView)}");

            //if (plot.ActualModel == null)
            //    throw new InvalidOperationException("Plot has no model");

            var controller = plot.ActualController;
            if (controller == null)
                throw new InvalidOperationException("Plot has no controller");

            if (e.OldValue is OxyMouseButton oldButton && oldButton != OxyMouseButton.None)
                controller.UnbindMouseDown(oldButton);

            var newButton = GetBindToMouseDown(d);
            if (newButton == OxyMouseButton.None)
                return;

            controller.UnbindMouseDown(newButton);
            controller.BindMouseDown(newButton, new DelegatePlotCommand<OxyMouseDownEventArgs>(
                AddStayOpenTrackerManipulator));
        }

        private static void AddStayOpenTrackerManipulator(IPlotView view, IController controller,
            OxyMouseDownEventArgs e)
        {
            controller.AddMouseManipulator(view, new StayOpenTrackerManipulator(view), e);
        }

        private class StayOpenTrackerManipulator : TrackerManipulator
        {
            private readonly PlotModel _plotModel;
            private bool _isTrackerOpen;

            public StayOpenTrackerManipulator(IPlotView plot)
                : base(plot)
            {
                _plotModel = plot?.ActualModel;

                Snap = true;
                PointsOnly = false;
            }

            public override void Started(OxyMouseEventArgs e)
            {
                if (_plotModel != null) { _plotModel.TrackerChanged += HandleTrackerChanged; }
                base.Started(e);
            }

            public override void Completed(OxyMouseEventArgs e)
            {
                if (!_isTrackerOpen)
                {
                    ReallyCompleted(e);
                }
                else
                {
                    // Completed() is called as soon as the mouse button is released.
                    // We won't call the base Completed() here since that would hide the tracker.
                    // Instead, defer the call until one of the hooked events occurs.
                    // The caller will still remove us from the list of active manipulators as soon as we return,
                    // but that's good; otherwise the tracker would continue to move around as the mouse does.
                    new DeferredCompletedCall(_plotModel, () => ReallyCompleted(e)).HookUp();
                }
            }

            private void ReallyCompleted(OxyMouseEventArgs e)
            {
                base.Completed(e);

                // Must unhook or this object will live as long as the model (instead of as long as the manipulation)
                if (_plotModel != null) { _plotModel.TrackerChanged -= HandleTrackerChanged; }
            }

            private void HandleTrackerChanged(object sender, TrackerEventArgs e) =>
                _isTrackerOpen = e.HitResult != null;

            /// <summary>
            /// Monitors events that should trigger manipulator completion and calls an injected function when they fire
            /// </summary>
            private class DeferredCompletedCall
            {
                private readonly PlotModel _plotModel;
                private readonly Action _completed;

                public DeferredCompletedCall(PlotModel plotModel, Action completed)
                {
                    _plotModel = plotModel;
                    _completed = completed;
                }

                /// <summary>
                /// Start monitoring events. Their observer lists will keep us alive until <see cref="Unhook"/> is called.
                /// </summary>
                public void HookUp()
                {
                    Unhook();

                    _plotModel.MouseDown += HandleMouseDown;
                    _plotModel.Updated += HandleUpdated;
                    _plotModel.MouseLeave += HandleMouseLeave;
                }

                /// <summary>
                /// Stop watching events. If they were the only things keeping us alive, we'll turn into garbage.
                /// </summary>
                private void Unhook()
                {
                    _plotModel.MouseDown -= HandleMouseDown;
                    _plotModel.Updated -= HandleUpdated;
                    _plotModel.MouseLeave -= HandleMouseLeave;
                }

                private void CallCompletedAndUnhookEvents()
                {
                    _completed();
                    Unhook();
                }

                private void HandleUpdated(object sender, EventArgs e) => CallCompletedAndUnhookEvents();

                private void HandleMouseLeave(object sender, OxyMouseEventArgs e) => CallCompletedAndUnhookEvents();

                private void HandleMouseDown(object sender, OxyMouseDownEventArgs e)
                {
                    CallCompletedAndUnhookEvents();

                    // Since we're not setting e.Handled to true here, this click will have its regular effect in
                    // addition to closing the tracker; e.g. it could open the tracker again at the new position.
                    // Modify this code if that's not what you want.
                }
            }
        }
    }

### 开发摄影测量空间前方交会的Windows Forms应用 创建一个基于C#的Windows Forms应用程序来实现摄影测量中的空间前方交会功能涉及多个方面,包括界面设计、数据处理逻辑以及算法实现。下面提供了一个简化版的空间前方交会计算方法,并展示了如何将其集成到Windows Forms应用程序中。 #### 创建项目并设置UI布局 首先,在Visual Studio中新建一个名为`PhotogrammetryApp`的Windows Forms App (.NET Framework)项目。接着修改默认生成的Form1.cs文件内的代码如下: ```csharp using System; using System.Drawing; using System.Windows.Forms; namespace PhotogrammetryApp { public partial class MainForm : Form { private Label lblResult; // 显示结果标签 public MainForm() { InitializeComponent(); this.Text = "摄影测量 - 空间前方交会"; InitializeComponents(); } /// <summary> /// 初始化组件 /// </summary> private void InitializeComponents(){ var gbInputData = new GroupBox { Text="输入参数", Location=new Point(10, 10), Size= new Size(380, 200)}; var btnCalculate = new Button{Text ="计算",Location =new Point (gbInputData.Left + 170 , gbInputData.Bottom + 10 ),Size =new Size (100 , 30 )}; lblResult = new Label { AutoSize=true, Location=new Point(gbInputData.Left,btnCalculate.Top+40)}; Controls.AddRange(new Control[]{gbInputData,btnCalculate,lblResult}); // 添加事件处理器 btnCalculate.Click += BtnCalculate_Click; } private void BtnCalculate_Click(object sender, EventArgs e){ try{ double[] pointA={/*...*/}; // A坐标 double[] pointB={/*...*/}; // B坐标 Tuple<double,double> result=SpatialForwardIntersection(pointA,pointB); string output=$"交X:{result.Item1:F6}\n"+"交Y:"+ $"{result.Item2:F6}"; lblResult.Text=output; }catch(Exception ex){ MessageBox.Show($"发生错误:\r\n{ex.Message}","提示"); } } /// <summary> /// 计算两个观测站之间的空间前方交会 /// </summary> /// <param name="stationAPosition">第一个观测站位置</param> /// <param name="stationBPosition">第二个观测站位置</param> /// <returns></returns> static Tuple<double,double> SpatialForwardIntersection(double[] stationAPosition,double[] stationBPosition){ /* 这里应该放置实际的空间前方交会算法 */ throw new NotImplementedException("此函数尚未完成具体实现."); } } } ``` 上述代码片段定义了基本的应用程序结构和用户交互流程[^1]。为了使这个例子更加实用,还需要补充具体的数学模型和解析几何运算以完成真正的空间前方交会计算部分。这部分通常涉及到复杂的三角学和平面/立体几何知识,可能需要查阅专门针对摄影测量学的相关资料或文献来进行深入研究。 对于更复杂的功能需求,比如图形化展示交汇过程或是支持更多类型的输入输出格式,则可以考虑引入第三方库或者工具集,如Math.NET Numerics用于数值分析,OxyPlot用来绘制图表等。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值