Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > WPF и Silverlight > Как добавить сетку на Canvas в WPF?


Автор: Anyone 24.7.2009, 10:50

Пишу контрол, производный от Canvas. Необходимо добавить сетку с возможностью изменения шага по горизонтали и вертикали(в виде точек желательно, накрайняк, пунктирных линий), к которой возможна привязка элементов Canvas'а. 
Ничего подобного я не нашел, потому хотел бы спросить каким образом лучше всего поступить?

Может быть лучше всего рисовать ее при обновлении Canvas'a (если да, то куда копать)?

Также есть другая идея - использовать Grid и выставить свойство ShowGridLines="True":
Код

<local:UgeDrawingCanvas x:Name="DrawingCanvas">
    <Grid Name="DrawingCanvasGrid" ShowGridLines="True" Width="{Binding DrawingCanvas.ActualWidth}" Height="{Binding DrawingCanvas.ActualHeight}"/>
</local:UgeDrawingCanvas>
 
Но этот вариант мне не нравится, потому что выходит очень не красиво, размеры ячеек немного колеблятся в зависимости от положения скроллов, снизу и справа иногда не прорисовывается сетка.
Смещаю таким образом:
Код

        private void ScrollBarHorisontal_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            Dx = - e.NewValue;
            SetScrollOffset(Dx, Dy);
        }

        private void ScrollBarVertical_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            Dy = - e.NewValue;
            SetScrollOffset(Dx, Dy);
        }
        private void SetScrollOffset(double dx, double dy)
        {
            foreach (var item in DrawingCanvas.Children)
            {
                DrawingCanvasGrid.SetValue(RenderTransformProperty, new TranslateTransform(dx%gridX, dy%gridY));

                UIElement uiElement = item as UIElement;
                if (uiElement != null)
                {
                    uiElement.SetValue(RenderTransformProperty,new TranslateTransform(dx,dy));
                }
            }
        }


И еще один вопрос, как можно изменить вид линий грида? хочу вообще заменить на точки.

Есть другие идеи?

Автор: Partizan 24.7.2009, 20:31
Anyone, ага...можно попробовать собственный adorner реализовать, в котором и отрисовывать соответствующую сетку линиями

Автор: Anyone 27.7.2009, 12:08
Цитата(Partizan @  24.7.2009,  20:31 Найти цитируемый пост)
ожно попробовать собственный adorner реализовать

Но при этом же сетка будет всегда сверху скорее всего... В принципе, если в виде точек ее реализовать, тоже не плохо, но думаю не всегда такое поведение желательно. Попробую, идея мне нравится.

Автор: rooks 28.7.2009, 01:38
а как насчет сделать бэкграунд с помощью DrawingBrush?
Код
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Page.Resources>
        <DrawingBrush x:Key="stripedBrush" Viewport="0,0,10,10" ViewportUnits="Absolute" TileMode="Tile">
            <DrawingBrush.Drawing>
                <GeometryDrawing Brush="Black">
                    <GeometryDrawing.Geometry>
                        <GeometryGroup FillRule="EvenOdd">
                            <RectangleGeometry Rect="0,0,10,10" />
                            <PathGeometry Figures="M 0,0 L 1,0 L 1,1 L 0,1z"/>
                            <RectangleGeometry Rect="0,0,10,10" />
                        </GeometryGroup>
                    </GeometryDrawing.Geometry>
                </GeometryDrawing>
            </DrawingBrush.Drawing>
        </DrawingBrush>
    </Page.Resources>
    <Grid Background="{StaticResource stripedBrush}">
    
    </Grid>
</Page>

Автор: Anyone 28.7.2009, 08:32
Цитата(rooks @  28.7.2009,  01:38 Найти цитируемый пост)
а как насчет сделать бэкграунд с помощью DrawingBrush?

А как в этом случае менять шаг сетки и смещать ее при прокрутке? Определить эти все свойства в моем производном классе а сетку определить в шаблоне с привязками к этим свойствам, или лучше програмно генерить и переприсваивать кисть? А вообще-то свойство Background мне еще пригодится для того чтоб задать фоновый рисунок или цвет, думаю заливать этой кистью какой-нить прямоугольник внутри канваса.

Автор: neiron 28.7.2009, 08:58
Шаг вполне можно менять скейлтрансформом. Хочешь увеличивай, хочешь уменьшай. скейл для самого Drawing, а не для канвы.
А смещать соответственно транслейтом

Автор: Anyone 28.7.2009, 09:00
Большое спасибо за помощь. Видимо, создавать кисть - наилучший вариант.

Автор: Anyone 28.7.2009, 09:19
Вот как я добавляю сетку:
Код

            <local:UgeDrawingCanvas x:Name="DrawingCanvas" Grid.Row="1" Grid.Column="1" Background="LightGray" ClipToBounds="True" SizeChanged="DrawingCanvas_SizeChanged">
            <Rectangle Name="DrawingCanvasGrid" Fill="{StaticResource stripedBrush}"/>
            </local:UgeDrawingCanvas>


И у меня пару вопросов:
1. Как сделать чтобы прямоугольник полностью залил всю область канваса?
2. Как с помощью ScaleTransform изменить шаг сетки так, чтобы размер точек оставался в 1 пиксел?
3. Как правильно использовать ScaleTransform для кисти? Для шага (25;50) я написал такой код:
Код

DrawingCanvasGrid.Fill.RelativeTransform = new ScaleTransform(5, 2.5);
 
Но при этом точки тоже отмасштабировались.

Автор: neiron 28.7.2009, 09:40
1. VerticalAligment = "Stretch" HorizontalAligment = "Stretch" для прямоугольника. Учитывая что он кистью отрисовывается - должен замостить канву.
2-3. Что-то в голову не приходит ничего простого. Только переопределение кисти. Операция не слишком трудозатратная, потому, думаю, латентности не добавит. кисти вроде бы freezable поддерживают - должны автоматом перерисовываться.

Автор: Anyone 28.7.2009, 09:47
Цитата(neiron @  28.7.2009,  09:40 Найти цитируемый пост)
1. VerticalAligment = "Stretch" HorizontalAligment = "Stretch" для прямоугольника. 

В том то и дело, что не помогает... Наверное придется програмно по актульным размерам канваса, что не очень то и хочется...

Цитата(neiron @  28.7.2009,  09:40 Найти цитируемый пост)
2-3. Что-то в голову не приходит ничего простого. Только переопределение кисти.

Вот и мне только это приходит в голову.

Добавлено через 9 минут и 9 секунд
А можно в этом случае использовать привязки к свойствам владельца кисти?
Код

        <DrawingBrush x:Key="stripedBrush" Viewport="{TemplateBinding ...}" ViewportUnits="Absolute" TileMode="Tile">
            <DrawingBrush.Drawing>
                <GeometryDrawing Brush="{TemplateBinding ...}">
                    <GeometryDrawing.Geometry>
                        <GeometryGroup FillRule="EvenOdd">
                            <RectangleGeometry Rect="{TemplateBinding ...}" />
                            <PathGeometry Figures="M 0,0 L 1,0 L 1,1 L 0,1z"/>
                            <RectangleGeometry Rect="{TemplateBinding ...}" />
                        </GeometryGroup>
                    </GeometryDrawing.Geometry>
                </GeometryDrawing>
            </DrawingBrush.Drawing>
        </DrawingBrush>

Тогда все эти свойства можно будет определить в канвасе (прямоугольнике).

Автор: Anyone 28.7.2009, 13:17
Попытался выполнить это с помощью стиля, но с привязкой данных ничего не получается (Brush="{Binding Stroke}"). 
Код

    <Style x:Key="DrawingCanvasGridStyle">
        <Setter Property="Rectangle.Fill">
            <Setter.Value>
                <DrawingBrush Viewport="0,0,50,50" ViewportUnits="Absolute" TileMode="Tile">
                    <DrawingBrush.Drawing>
                        <GeometryDrawing Brush="{Binding Stroke}">
                            <GeometryDrawing.Geometry>
                                <GeometryGroup FillRule="EvenOdd">
                                    <RectangleGeometry Rect="0,0,50,50" />
                                    <PathGeometry Figures="M 0,0 L 2,0 L 2,2 L 0,2z"/>
                                    <RectangleGeometry Rect="0,0,50,50" />
                                </GeometryGroup>
                            </GeometryDrawing.Geometry>
                        </GeometryDrawing>
                    </DrawingBrush.Drawing>
                </DrawingBrush>
            </Setter.Value>
        </Setter> 
    </Style>

Что я делаю не так?

Автор: Anyone 28.7.2009, 17:03
Также попытался програмно создавать кисть, но ничего не получилось:

Код

        private DrawingBrush DefineBrush(double x, double y, int width, Color color)
        {
            GeometryDrawing geometryDrawing = new GeometryDrawing();
            RectangleGeometry rectangleGeometry 
                = new RectangleGeometry(new Rect(x / 2 - width, y / 2 - width, width, width));
            geometryDrawing.Geometry = rectangleGeometry;
            geometryDrawing.Brush = new SolidColorBrush(color);
            geometryDrawing.Pen=new Pen(new SolidColorBrush(color),1);

            return new DrawingBrush(geometryDrawing);
        }

Автор: Anyone 29.7.2009, 09:06
Решил задачу с помощью програмной кисти. 
Всем спасибо за помощь. 
Правда хотелось бы еще попробывать с помощью шаблона\стиля, буду благодарен за подсказку по поводу привязки параметров кисти к свойствам контрола.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)