14 февраля 2011 г.

Silverlght: Бадания с Canvas

Простая задача. Необходимо на странице разместить в экземпляре ScrollViewer разместить  Canavas, а в нем уже изображение, TextBox или что-то еще. Делалось с той целью, чтобы получился такой объект в него можно было добавлять новые компоненты (помимо Image или TextBox), а он при этом растягивался и оставлял для доступа «ползунок” . Зараза Canvas, совсем не так работает как предполагалось. Скриншот тогда не сделал, поэтому не могу продемонстрировать — все содержимое обрезалось по фактическому размеру ScrollViewer (полоса прокрутки не потребовалась).
Озарение: Canvas не определяет свой размер по размеру дочернего элемента.
Второй целью этой задачи было создать компонент, который сможет не только справится с выше озвученной проблемой, но и сможет принимать новые параметры. Понятным языком — необходимо сделать доступным в xaml разметке компонента пользовательские свойства, через которые можно передавать параметры новому компоненту.
Озарение: Для создания пользовательских свойств компонента, доступных в xaml разметки необходимо использовать объект   свойств зависимостей public static readonly DependencyProperty.
 И так, постановка задачи:
1) Любой ценой разместить Canvas в ScrollViewer;
2) Реализовать эту задачу, как чисто в xaml так и чисто в C# (создав компонент)
3) Привести пример использование DependencyProperty

Замечание: Добавлять Canvas в ScrollViewer напрямую не удастся, вместо этого в ScrollViewer будет вложен Grid, в нем что угодно, в том числе Canvas. Все прочее что необходимо будет добавить добавляем в Grid:
Реализация на xaml:
<ScrollViewer HorizontalScrollBarVisibility="Auto"  Width="auto" Height="auto" Grid.Column="0" Grid.Row="1">
    <ScrollViewer.Content>
        <!-- Объект Canvas вложенный В объект ScrollViewer примет размер Scroll viewer и не будет учитывать
        рамер объектов размещенных в  Canvasе!! - поэтому используется Grid, а в нем Canvas -->

        <Grid Width="auto" Height="auto" >
            <!-- Смастерим просмотрщик: Размер Gridа будет под размер изображения-->
            <Image x:Name="loadedImage" Width="auto" Height="auto">
               <Image.RenderTransform>
               <CompositeTransform ScaleX="1" ScaleY="1"/><!-- Задел для масштабирования-->
               </Image.RenderTransform>
               </Image>
            <!-- Если не все дочерние эл-ты в Grid разместить в одной ячейки то они могут идти как два слоя  -->
               <Canvas Background="Transparent" >
               <!-- Поверх Image будет прозрачный Холст, а на нем кнопка (можно заменить на что, нибудь другое) -->
                <Button Content="It s Canvas" Canvas.Left="100" Canvas.Top="100"/>
              <!-- Вообщим Canvas будет такого-же размера как и  Image -->
            </Canvas>
        </Grid>
    </ScrollViewer.Content>
</ScrollViewer>Syhi-подсветка кода
Реализация компонента на C#:
// Небольшой класс реализующий возможность простых манипуляций изображений
// В данном случае возможность просмотра изображения превышающего размер окна
public class ImageManipulate : ContentControl
{
    // Добавляем произвольное свойство к создаваемому компоненту - исходное изображение
    public static readonly DependencyProperty SourceProperty =
        DependencyProperty.Register("Source", typeof(Image),typeof(ImageManipulate), null);
    //Дополнительное свойство позволяющее принимать canvas как параметр в xaml разметке
    public static readonly DependencyProperty CanvasInsideProperty =
        DependencyProperty.Register("CanvasInside", typeof(Canvas), typeof(ImageManipulate), null);
    private double _imageWidth;     // Ширина оригинального изображения
    private double _imageHeight;    // Высота оригинального изображения
    private Image _image;           // Изображение для возможных манипуляций
    private ScrollViewer viewerBox;
    private Grid mainGridContainer;
        //Свойство которое и осуществляет прием  и передачу изображения
    public Image Source
    {
                get { return (Image)GetValue(SourceProperty); }
        set
            {
            SetValue(SourceProperty, value);
            _image = value;//Кэшируем изображение
            _imageWidth = _image.Width;
            _imageHeight = _image.Height;
            this.mainGridContainer.Children.Add(this._image);//Добавляем изображение в Grid
            }
    }
    public Canvas CanvasInside
    {
        get { return (Canvas)GetValue(CanvasInsideProperty); }
        set
        {
            SetValue(CanvasInsideProperty, value);
            this.mainGridContainer.Children.Add(value);
        }
    }
    public ImageManipulate()
    {
        this.mainGridContainer = new Grid();
        viewerBox = new ScrollViewer() { HorizontalScrollBarVisibility = ScrollBarVisibility.Auto };
        viewerBox.Content = this.mainGridContainer;// Создаем объект контейнера с "ползунками" и добаляем в него Грид
        this.Content = viewerBox;
    }
}Syhi-подсветка кода
Его ре инкарнация в xaml разметке:
<!-- xmlns:local="clr-namespace:FotoDocDemo1;assembly=FotoDocDemo1" - ссылаемся на пространство имен
в котором находится класс ImageManipulate-->

<local:ImageManipulate Grid.Row="1" Width="auto" Height="auto">
        <!-- Свойство Source: -->
    <local:ImageManipulate.Source>
        <Image Source="img/avstria.jpg" Width="auto" Height="auto"/>
    </local:ImageManipulate.Source>
        <!-- Свойство CanvasInside-->
    <local:ImageManipulate.CanvasInside>
        <Canvas Width="auto" Height="auto">
            <Button Content="Click" Canvas.Left="200" Canvas.Top="200"/>
        </Canvas>
</local:ImageManipulate.CanvasInside>
</local:ImageManipulate>Syhi-подсветка кода

Комментариев нет:

Отправить комментарий