как нарисовать N линий на дюйм?

мой код ниже должен отображать N строк на дюйм. вместо этого я получаю чуть больше N линий на дюйм. расстояние между строками несколько меньше. кроме того, изменение разрешения экрана приводит к изменению расстояния между линиями. кто-нибудь знает, как с этим справиться?


using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace MyApp
{
    class MyControl : Control
    {
        private readonly ContainerVisual container = new ContainerVisual();
        private readonly DrawingVisual drawing = new DrawingVisual();

        private void RenderDrawing()
        {
            var s = PresentationSource.FromVisual(this);
            var dpiX = 96 * s.CompositionTarget.TransformToDevice.M11;
            var dpiY = 96 * s.CompositionTarget.TransformToDevice.M22;

            double N = 1;

            using (var c = drawing.RenderOpen())
            {
                var p = new Pen(new SolidColorBrush(Colors.Black), 1);

                for (int i = 0; i < 10; i++)
                {
                    var x = i * dpiX / N;
                    c.DrawLine(p, new Point(x, 0), new Point(x, 100));
                }
            }
        }

        protected override Size ArrangeOverride(Size s)
        {
            RenderDrawing();
            return s;
        }

        protected override Visual GetVisualChild(int index)
        {
            return container;
        }

        protected override Size MeasureOverride(Size s)
        {
            return new Size();
        }

        protected override int VisualChildrenCount
        {
            get { return 1; }
        }

        public MyControl()
        {
            container.Children.Add(drawing);
            AddVisualChild(container);
        }
    }
}

person akonsu    schedule 22.11.2010    source источник
comment
Я предполагаю, что это всего лишь пример кода, но похоже, что вы всегда будете рисовать 10 линий. Не N линий на дюйм. Я мог что-то упустить, но я почти уверен, что цикл for от 0 до 9 будет рисовать 10 линий. Кроме того, вы должны поместить Pen в оператор using (используя var p = new Pen ...), иначе вы получите утечку дескрипторов GDI.   -  person pstrjds    schedule 22.11.2010
comment
да, это пример кода. да, он рисует десять линий. предполагается провести эти десять линий так, чтобы они находились на расстоянии 1 / N дюйма друг от друга.   -  person akonsu    schedule 22.11.2010
comment
Хорошо, я бы, возможно, отредактировал вопрос, чтобы объяснить это, я прочитал его, так как вы хотите N строк на дюйм, а не 10 строк с расстоянием 1 / N между ними. На самом деле, читая ваш вопрос еще раз, я немного сбит с толку, вы говорите, что зазор изменяется при изменении разрешения, но это именно то, что вы хотите, если вам нужно только 10 строк с расстоянием между ними в зависимости от текущего разрешения, тогда расстояние изменяется при изменении разрешения.   -  person pstrjds    schedule 22.11.2010
comment
Кажется, это недоразумение ... я хочу, чтобы плотность линий составляла N линий на дюйм, но не имеет значения, сколько линий я рисую ... десять или сто. N линий на дюйм делает расстояние между ними равным 1 / N дюйма.   -  person akonsu    schedule 22.11.2010
comment
Хорошо, в этом случае интервал будет меняться по мере настройки разрешения, но я бы порекомендовал, возможно, вычислить dpiX / N вне цикла и проверить, что это за значение. Я думаю, у вас могут быть проблемы с округлением. Запустите его под отладчиком и проверьте значение dpiX / N. На первый взгляд код кажется подходящим для вашего интервала.   -  person pstrjds    schedule 22.11.2010
comment
Что ж, я верю, вы в основном вычисляете DPI 96 в своем коде. Я думаю, вы хотите перевести другое направление. Если вы хотите, чтобы линии были разнесены на 96 точек на дюйм, вычислите местоположение, но затем преобразуйте эти координаты в элемент управления. По крайней мере, это то, что я бы сделал, мне нравится вычислять массив точек, а затем прогонять все это через матрицу преобразования сразу, а не вычислять округленное dpi и использовать его.   -  person pstrjds    schedule 22.11.2010


Ответы (2)


эта статья, кажется, обсуждает ту же проблему: Проблемы WPF DPI, для этой проблемы нет другого решения, кроме как спросить пользователь, чтобы установить правильные настройки DPI, соответствующие физическому DPI экрана. Обходной путь, который, как я обнаружил, немного упрощает жизнь, - это использовать масштабирование на уровне приложения WPF, как описано здесь: http://www.odewit.net/ArticleContent.aspx?id=WpfDpiScaling&lang=en&format=html

person akonsu    schedule 23.11.2010
comment
Я решил, что проблема связана с различиями в разрешении и округлением. Я много работаю над разработкой интерфейсов, чтобы пользователи могли редактировать информацию с изображений. Масштабирование и разрешение - одни из самых сложных вещей, с которыми приходится иметь дело (что происходит с полем, когда пользователь увеличивает или уменьшает масштаб, что происходит, когда он меняет свое разрешение, и т. Д.). Похоже, что класс перспективы (ссылка на которую приведена в связанной статье: перспектива.codeplex.com выполнит то, что вам нужно . - person pstrjds; 23.11.2010

Не уверен, что это поможет достичь того, что вы ищете, но должно помочь, если проблема связана с округлением. Как я сказал в комментариях, ваш код выглядит в основном правильным, я думаю, что это проблема округления при вычислении dpi. Поскольку вы хотите визуализировать на основе 96 точек на дюйм, вычислите координаты на основе 96 точек на дюйм, а затем преобразуйте точки в свое устройство. Я написал это больше для ясности, вы можете использовать один массив точек и просто помните, что i - это начальная точка, а i+1 - конечная точка, и тогда вам нужно будет сделать только один вызов для преобразования точек.

    private void RenderDrawing()
    {
        var s = PresentationSource.FromVisual(this);
        var dpiX = 96;

        int numberOfLines = 10;
        double N = 1;
        double spacing = dpiX / N;

        var startPoints = new Point[numberOfLines]();
        var endPoints = new Point[numberOfLines]();
        for (int i = 0; i < numberOfLines; i++)
        {
            var x = i * spacing;
            startPoints[i] = new Point(x, 0);
            endPoints[i] = new Point(x, 100);                 
        }
        s.CompositionTarget.TransformToDevice.Transform(startPoints);
        s.CompositionTarget.TransformToDevice.Transform(endPoints);

        using (var c = drawing.RenderOpen())
        {
            using (var p = new Pen(new SolidColorBrush(Colors.Black), 1))
            {
                 for(int i=0; i < numberOfLines; i++)
                 {
                    c.DrawLine(p, startPoints[i], endPoints[i]);
                 }
            }
        }
    }
person pstrjds    schedule 22.11.2010
comment
Спасибо за вашу помощь. похоже, вы не избежали знака «меньше чем» во второй строке ... - person akonsu; 22.11.2010
comment
хороший улов, я намеревался вырезать / вставить строку, когда редактировал, и, по-видимому, вместо этого скопировал / вставил. Должен быть исправлен сейчас. - person pstrjds; 22.11.2010