【问题标题】:Impossible results due to property changed event being slow由于属性更改事件缓慢而导致不可能的结果
【发布时间】:2016-05-16 15:32:38
【问题描述】:

我本来想发个问题,多线程同步代码怎么可能出现以下情况:

但我在写问题时想出了答案:在计算时,等式中的被除数似乎为零,但之后会迅速改变值(注意:这个错误是罕见的,复制非确定性地,通常当我在 DataGrid 上使用向上/向下箭头时)。

相关代码如下:

        public double? LeftPolyArea => Model.GetArea(LeftPolyName);
        public double? RightPolyArea => Model.GetArea(RightPolyName);
        public double? RightPolyNonOverlappingArea =>Model.GetNonOverlappingArea(RightPolyName, LeftPolyName);
        public double? ResemblenceIndex
        {
            get
            {
                if (!(LeftPolyOverlappingArea.HasValue && LeftPolyArea.HasValue && RightPolyArea.HasValue)) return null;
                var index = LeftPolyOverlappingArea.Value / ((LeftPolyArea.Value + RightPolyArea.Value) / 2) * 100;
                return Math.Round(index, 1);
            }
        }

NotifyPropertyChanged 事件会立即触发:

public void Refresh()
        {
            OnPropertyChanged(nameof(LeftPolyArea));
            OnPropertyChanged(nameof(RightPolyArea));
            OnPropertyChanged(nameof(ResemblenceIndex));
        }

我知道如果我坚持通常的 Notify 属性,它就不会发生,但我真的不明白,为什么它不能按原样工作。如果这两个触发的事件更改了一些现有变量,我会理解它,而不是快速访问会产生“旧”值,但这些是获取属性,所以控制流在计算完成之前不应该继续,对吧?这里有什么问题?

[编辑] 我正在添加模型代码: [EDIT2] 几乎完整的模型代码:

public class SpatialMapsModel : ISpatialMapsModel
{
    public int RoundDigits { get; set; } = 1;

    public IOService InputOutputService { get; }

    public SpatialMapsModel(IOService ioService)
    {
        InputOutputService = ioService;
    }

    public bool IsPolygonValid(IList<C2DPoint> polygon)
    {
        return polygon?.Count > 2
    }

    public enum IntersectionType
    {
        Overlapping,
        NonOverlapping
    }

    public List<C2DHoledPolygon> GetIntersectingPolygons(IList<C2DPoint> pointsA, IList<C2DPoint> pointsB, IntersectionType whichPolygons)
    {
        var leftPoly = new C2DPolygon(pointsA.ToList(), true);
        var rightPoly = new C2DPolygon(pointsB.ToList(), true);
        rightPoly.RandomPerturb();
        var someGrid = new CGrid();
        var smallPolygons = new List<C2DHoledPolygon>();
        switch (whichPolygons)
        {
            case IntersectionType.Overlapping:
                leftPoly.GetOverlaps(rightPoly, smallPolygons, someGrid);
                break;
            case IntersectionType.NonOverlapping:
                leftPoly.GetNonOverlaps(rightPoly, smallPolygons, someGrid);
                break;
            default:
                throw new ArgumentException(nameof(whichPolygons));
        }
        return smallPolygons;
    }

    public double? GetOverlappingArea(IList<C2DPoint> pointsA, IList<C2DPoint> pointsB)
    {
        var polygons = GetIntersectingPolygons(pointsA, pointsB, IntersectionType.Overlapping);
        var area = polygons.Sum(p => p.GetArea());
        return Math.Round(area, RoundDigits);
    }

    public double? GetNonOverlappingArea(IList<C2DPoint> pointsA, IList<C2DPoint> pointsB)
    {
        var polygons = GetIntersectingPolygons(pointsA, pointsB, IntersectionType.NonOverlapping);
        var area = polygons.Sum(p => p.GetArea());
        return Math.Round(area, RoundDigits);
    }

    private Tuple<double, double, double, double> MinMax(IList<C2DPoint> input)
    {
        var minX = double.MaxValue;
        var minY = double.MaxValue;
        var maxX = double.MinValue;
        var maxY = double.MinValue;
        foreach (var t in input)
        {
            if (t.X < minX)
                minX = t.x;
            if (t.y < minY)
                minY = t.y;
            if (t.X > maxX)
                maxX = t.x;
            if (t.y > maxY)
                maxY = t.y;
        }
        return new Tuple<double, double, double, double>(minX, minY, maxX, maxY);
    }
    public void SnapToOriginInPlace(IList<C2DPoint> input)
    {
        var minXy = MinMax(input);
        for (var i = 0; i < input.Count; ++i)
        {
            input[i] = new C2DPoint(input[i].X - minXy.Item1, input[i].Y - minXy.Item2);
        }
        var poly = new C2DPolygon(input.ToList(), true);
        poly.RandomPerturb();
        var pointsCopy = new C2DPointSet();
        poly.GetPointsCopy(pointsCopy);
        for (var i = 0; i < pointsCopy.Count; ++i)
        {
            input[i] = pointsCopy[i];
        }
    }
    public KeyValuePair<string, List<C2DPoint>> GetPolygonFromFile(string fileName){...}

    public void WritePolygonToFile(IList<C2DPoint> poly, string fileName){...}

    public double? GetArea(IList<C2DPoint> points)
    {
        if (IsPolygonValid(points))
        {
            var poly = new C2DPolygon(points.ToList(), true);
            var area = poly.GetArea();
            return Math.Round(area, RoundDigits);
        }
        return null;
    }

    public double? GetPerimeter(IList<C2DPoint> points){...}
}

【问题讨论】:

  • 您知道所有 UI 都是单线程的,并且属性更改事件没有在多个线程上运行吗?
  • 没有多线程
  • 我们能看到Model的代码吗?
  • 我会在几秒钟内发布相关的电话,但没有免费的工作人员、任务、线程或等待对象,如果那是你所追求的。只是库调用。
  • 虽然不是不可能,但很可能发生的数学不一致地试图弄清楚括号在说什么。按照您显示的值45829.5 / ((45829.5 + 45829.5) / 2) * 100 是您的等式。这等于45829.5 / (45829.5) * 1001 * 100。尝试将您的算法更改为 (45829.5 / ((45829.5 + 45829.5) / 2)) * 100 可能完全没有区别,但值得一试

标签: c# c#-6.0


【解决方案1】:

问题来自我使用的库 GeoLib,当一个点的 X 或 Y 值与其他 X 或 Y 值完全相等时,出现重叠。随机扰动应防止这种情况发生,但偶尔(随机......)不会这样做,尤其是在缩放和变换多边形时。但是它仍然没有回答,为什么在计算过程中值会发生变化。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-26
    • 2011-07-07
    • 2019-01-27
    • 2017-03-27
    • 1970-01-01
    • 2018-05-02
    • 2021-11-11
    • 1970-01-01
    相关资源
    最近更新 更多