none
Problem with visual brushes pointing to elements outside the visual tree

    Question

  • I’m writing a designer application whose interface imitates PowerPoint. The central part of the window is a grid with a splitter. At the left hand side I want to show a preview of each layout page on a button and at the right hand side only the layout page that is currently being edited. In XAML it looks like this:

                <Grid>

                    <Grid.ColumnDefinitions>

                        <ColumnDefinition Width="200" MinWidth="0" MaxWidth="300" />

                        <ColumnDefinition Width="Auto" />

                        <ColumnDefinition Width="*" />

                    </Grid.ColumnDefinitions>

                    <ScrollViewer VerticalScrollBarVisibility="Auto">

                        <ItemsControl ItemTemplate="{StaticResource LayoutPagePreviewTemplate}">

                            <ItemsControl.ItemsSource>

                                <local:cedLayoutPagePreviewCollection x:Name="clnLayoutPagePreviews" />

                            </ItemsControl.ItemsSource>

                        </ItemsControl>

                    </ScrollViewer>

                    <GridSplitter Grid.Column="1" Width="6" VerticalAlignment="Stretch" HorizontalAlignment="Center"

                            Background="{Binding ElementName=objRibbon, Path=Background}"

                            BorderBrush="{Binding ElementName=objRibbon, Path=BorderBrush}" BorderThickness="1,0" />

                    <ScrollViewer Name="objScrollViewer" Grid.Column="2" VerticalScrollBarVisibility="Auto"

                            HorizontalScrollBarVisibility="Auto" />

                </Grid>

     

    In code, I set the child of the scroll viewer on the right side to a custom layout object that I developed myself. This layout object contains all layout pages with functionality for opening, saving, printing, etcetera. The object is capable of showing all layout pages in a grid-like fashion, but it has also an IsDesigning property that causes only the current layout page to be shown. I also fill the clnLayoutPagePreview collection in code with cedLayoutPagePreview objects. These objects contain a property called LayoutPage that is a reference to the respective layout page in the layout object. The LayoutPagePreviewTemplate is defined as shown below:

            <DataTemplate x:Key="LayoutPagePreviewTemplate">

                <Button Padding="5,5" Command="local:cedTemplateCommands.SelectPage" CommandParameter="{Binding LayoutPage}">

                    <Button.Template>

                        <ControlTemplate>

                            <Border x:Name="MainBorder" BorderThickness="1" Margin="5,5,5,0">

                                <Viewbox Margin="15,5,5,5">

                                    <Border Background="White">

                                        <Rectangle Width="{Binding LayoutPage.ActualWidth}"

                                                Height="{Binding LayoutPage.ActualHeight}"

                                                Stroke="{Binding ElementName=objRibbon, Path=BorderBrush}">

                                            <Rectangle.Fill>

                                                <VisualBrush Visual="{Binding LayoutPage}" />

                                            </Rectangle.Fill>

                                        </Rectangle>

                                    </Border>

                                </Viewbox>

                            </Border>

                            <ControlTemplate.Triggers>

                                <Trigger Property="IsMouseOver" Value="True">

                                    <Setter TargetName="MainBorder" Property="Background"

                                            Value="{Binding ElementName=objRibbon, Path=MouseOverBackground}" />

                                    <Setter TargetName="MainBorder" Property="BorderBrush"

                                            Value="{Binding ElementName=objRibbon, Path=MouseOverBorderBrush}" />

                                </Trigger>

                            </ControlTemplate.Triggers>

                        </ControlTemplate>

                    </Button.Template>

                </Button>

            </DataTemplate>

     

    As you can see, I use a VisualBrush to show a preview of the layout page on a button. The layout pages are contained in the layout object that is shown on the right hand side.

    I want the layout object to show only a single page, but I still want the visual brushes to show previews of all pages. To achieve that, I make sure that I always call the measure and arrange methods of all pages, irrespective of whether they are shown or not, but the invisible pages are not included in the visual children collection of the layout object, to avoid that they are actually shown. My problem is that only the preview of the visible page always shows correctly. The previews of the invisible pages initially show wrong if I fill clnLayoutPagePreviews collection. With wrong I mean that they show a subsection of the layout page instead of the entire layout page and that the preview disappear when I move the mouse over them. As soon as the layout object is forced to repaint (for example by changing its Zoom property), the previews show correctly. When I set the layout object to the mode where all pages are shown in a grid-like fashion, the problem does not occur. It only happens with pages that are not part of the visual tree.

    I know this is a complex situation, but any suggestions are appreciated.

    kind regards, 
    Rutger Koperdraad.
    Tuesday, May 31, 2011 9:31 PM

Answers

  • Hi Min Zhu,

    I actually managed to solve the problem. Unlike the sample, the layout pages did not have their Width and Height properties set explicitly in the real project. The reason for that was that the page size was implemented as a property of the parent object, while the pages could only differ in their protrait/landscape setting. Now, while measuring the parent object, I set the Width and Height properties of all pages explicitly and that solves the problem. It seams that visual brush did not know well what size of the original object was and got into trouble because of that.

    Thanks for your help!


    Rutger Koperdraad.
    • Marked as answer by cucucucu Monday, June 06, 2011 4:48 PM
    Monday, June 06, 2011 4:48 PM

All replies

  • Hi cucucu,

    Could you please also post the code of the visual which is used in the visual brush, and kindly elaborate which part of the visual shows incorrectly?

    To troubleshoot this issue, I suggest you to use the WPF Tree Visualizer to browser the visual tree. (It is available in VS2010. Try Snoop if you uses other version of VS). Or use the VisualTreeHelper to go throught the visual tree by yourself. This could provide helpful hints about which is incorrect in the visual tree.

    I suspect the issue is because some components didn't build their visual tree since they are not connected with the rendering surface (i.e. not in the visual tree of the window).

    To resolve this issue, I suggest you to add all pages into the visual tree and set their Visibility to Hidden to hide them. Or you can use a ListBox to load all pages, and adjust the size of the ListBox and the pages to make sure only one page will be displayed at a time.

    Hope this helps.

    Best regards,


    Min Zhu [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.


    Wednesday, June 01, 2011 2:32 AM
    Moderator
  • Hi cucucu,

    Just checking in to see if the information was helpful. Please let us know if you would like further assistance.

    Have a great day!


    Min Zhu [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Friday, June 03, 2011 1:48 AM
    Moderator
  • Hi Min Zhu,

    Unfortunately, the visual object is too complex and confidential to post in it entirely. I would have to work out a simplified example to post, so please, give me some time.

    The central idea of the visual object, called cedTemplate, inherited from FrameworkElement, is that it has a collection of cedLayout objects, also inherited from FrameworkElement. The cedLayout object has a collection of cedLayoutage objects, which inherit from the Panel object and can contain children of different types, like TextBlock or Image. To save my cedTemplate object to a file, I use the XAML, so it has some importance for me to keep the XAML tidy and simple.

    I tried your suggestion to hide or collapse pages that should not been shown, but if I do that the VisualBrush is not showing anything either, so that does not work.

    The documentation suggests that a Visual doesn't need to be actually visual to be shown in a VisualBrush. The fact that it works after changing the zoom setting of the cedTemplate object and thus forcing it to repaint suggests that it can work. It is just that it is initially not showing correctly.

    thanks for your help,


    Rutger Koperdraad.
    Friday, June 03, 2011 2:07 AM
  • Hi Rutger Koperdraad,

    Thanks for the update. Take your time.

    It's true that a visual doesn't need to e actually visual to be shown in a VisualBrush, what I suspect is the visual tree has not been completely constructed in the first place. For example, a ContentPresent will not load the ContentTemplate until it is connected to a rendering surface.

    I think you can try the ListBox approach to resolve this issue.

    Something like this,

        <ListBox Height="200" Name="list" ScrollViewer.CanContentScroll="True">
          <ListBox.ItemContainerStyle>
            <Style TargetType="ListBoxItem">
              <Setter Property="MinHeight" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ListBox}, Path=ActualHeight}"/>
            </Style>
          </ListBox.ItemContainerStyle>
          <ListBoxItem>Page1</ListBoxItem>
          <ListBoxItem>Page2</ListBoxItem>
          <ListBoxItem>Page3</ListBoxItem>
          <ListBoxItem>Page4</ListBoxItem>
          <ListBoxItem>Page5</ListBoxItem>
        </ListBox>
    

     

    Best regards,

     

     


    Min Zhu [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Friday, June 03, 2011 2:59 AM
    Moderator
  • Hi Min Zhu,

    I created a simplified version of the project that shows how I implemented the PowerPoint-style page-selection tool bar. However, this simplified version works perfectly fine and doesn’t show the problem I have in my real project. For those who are interested, I post the code below.

     

    MainWindow.xaml

    <Window x:Class="MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:VisualBrushes"
            Title="Visual brushes" Height="350" Width="550">

        <Window.Resources>

            <RoutedUICommand x:Key="SelectPage" Text="Select page" />

            <Style x:Key="LayoutPagePreviewStyle">
                <Setter Property="Control.Background" Value="Transparent" />
                <Setter Property="Control.BorderBrush" Value="Transparent" />
                <Setter Property="Control.BorderThickness" Value="1" />
                <Style.Triggers>
                    <Trigger Property="UIElement.IsFocused" Value="True">
                        <Setter Property="Control.Background" Value="Red" />
                        <Setter Property="Control.BorderBrush" Value="DarkRed" />
                    </Trigger>
                    <Trigger Property="ToggleButton.IsChecked" Value="True">
                        <Setter Property="Control.Background" Value="Green" />
                        <Setter Property="Control.BorderBrush" Value="DarkGreen" />
                    </Trigger>
                    <Trigger Property="UIElement.IsMouseOver" Value="True">
                        <Setter Property="Control.Background" Value="LightGreen" />
                        <Setter Property="Control.BorderBrush" Value="Green" />
                    </Trigger>
                    <Trigger Property="Button.IsPressed" Value="True">
                        <Setter Property="Control.Background" Value="Yellow" />
                        <Setter Property="Control.BorderBrush" Value="Gold" />
                    </Trigger>
                </Style.Triggers>
            </Style>

            <DataTemplate x:Key="LayoutPagePreviewTemplate">
                <RadioButton Command="{StaticResource SelectPage}" CommandParameter="{Binding LayoutPage}"
                        GroupName="LayoutPagePreviews" IsChecked="{Binding IsChecked, Mode=TwoWay}" Margin="5,5,5,0"
                        Style="{StaticResource LayoutPagePreviewStyle}" ToolTip="{Binding ToolTip}">
                    <RadioButton.Template>
                        <ControlTemplate>
                            <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}"
                                    BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="2">
                                <Grid>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="Auto" />
                                        <ColumnDefinition Width="*" />
                                    </Grid.ColumnDefinitions>
                                    <TextBlock FontWeight="Bold" Foreground="{TemplateBinding Foreground}" Margin="5"
                                            Text="{Binding PageNumber}" />
                                    <Viewbox Grid.Column="1" Margin="0,5,5,5">
                                        <Border Background="White">
                                            <Rectangle Height="{Binding LayoutPage.ActualHeight}"
                                                    Width="{Binding LayoutPage.ActualWidth}" Stroke="LightBlue">
                                                <Rectangle.Fill>
                                                    <VisualBrush Visual="{Binding LayoutPage}" />
                                                </Rectangle.Fill>
                                            </Rectangle>
                                        </Border>
                                    </Viewbox>
                                </Grid>
                            </Border>
                        </ControlTemplate>
                    </RadioButton.Template>
                </RadioButton>
            </DataTemplate>

        </Window.Resources>

        <Window.CommandBindings>
            <CommandBinding Command="{StaticResource SelectPage}" Executed="SelectPageCommand_Executed" />
        </Window.CommandBindings>

        <Grid Background="LightBlue">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="150" />
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <ScrollViewer VerticalScrollBarVisibility="Auto">
                <ItemsControl ItemTemplate="{StaticResource LayoutPagePreviewTemplate}">
                    <ItemsControl.ItemsSource>
                        <local:cedLayoutPagePreviewCollection x:Name="clnLayoutPagePreviews" />
                    </ItemsControl.ItemsSource>
                </ItemsControl>
            </ScrollViewer>
            <GridSplitter Grid.Column="1" Width="6" VerticalAlignment="Stretch" HorizontalAlignment="Center"
                    Background="LightBlue" BorderBrush="Blue" BorderThickness="1,0" />
            <ScrollViewer Name="objWorkArea" Grid.Column="2" VerticalScrollBarVisibility="Auto"
                    HorizontalScrollBarVisibility="Auto" />
        </Grid>
    </Window>

     

    MainWindow.xaml.vb

    Class MainWindow

        Private m_objCurrentLayout As cedLayout

    #Region " Events "

        Private Sub MainWindow_Loaded(sender As Object, e As System.Windows.RoutedEventArgs) Handles Me.Loaded

            ' Create a new layout object
            m_objCurrentLayout = CreateNewLayout()

            ' Display the layout object in the right portion of the window
            objWorkArea.Content = m_objCurrentLayout

            ' Update the layout-page previews
            Call UpdateLayoutPagePreviews()

        End Sub

        Private Sub SelectPageCommand_Executed(ByVal sender As Object, ByVal e As ExecutedRoutedEventArgs)
            Try
                Dim objSelectedPage As cedLayoutPage = TryCast(e.Parameter, cedLayoutPage)

                If Not objSelectedPage Is Nothing Then
                    For Each objLayoutPage As cedLayoutPage In m_objCurrentLayout.LayoutPages
                        If objLayoutPage Is objSelectedPage Then
                            m_objCurrentLayout.CurrentLayoutPageIndex = m_objCurrentLayout.LayoutPages.IndexOf(objLayoutPage)
                        End If
                    Next
                End If
            Catch ex As Exception
                Call MessageBox.Show(ex.Message, ex.GetType.ToString, MessageBoxButton.OK)
            End Try
        End Sub

    #End Region

    #Region " Other methods "

        Private Function CreateNewLayout() As cedLayout
            Dim objLayout As New cedLayout With {.HorizontalAlignment = Windows.HorizontalAlignment.Center, _
                                                 .VerticalAlignment = Windows.VerticalAlignment.Center, _
                                                 .Margin = New Thickness(10)}
            Dim objPage1 As New cedLayoutPage With {.Width = 300, .Height = 200, .Name = "Front"}
            Dim objPage2 As New cedLayoutPage With {.Background = Brushes.AliceBlue, .Width = 300, .Height = 200, .Name = "Back"}
            Dim objBackground As New Image With {.Source = GetImage("Background")}
            Dim objPhoto As New Image With {.Source = GetImage("Photo"), .Width = 60, .Height = 80}
            Dim objName As New TextBlock With {.Text = "Rutger Koperdraad", .FontSize = 24, .Foreground = Brushes.White}
            Dim objText As New TextBlock With {.Text = "This is the back side", .FontSize = 24, .Foreground = Brushes.Black, _
                                               .Width = 300, .TextAlignment = TextAlignment.Center}

            Call Canvas.SetLeft(objPhoto, 20)
            Call Canvas.SetTop(objPhoto, 20)
            Call Canvas.SetLeft(objName, 20)
            Call Canvas.SetTop(objName, 150)
            Call Canvas.SetLeft(objText, 0)
            Call Canvas.SetTop(objText, 85)

            Call objLayout.LayoutPages.Add(objPage1)
            Call objLayout.LayoutPages.Add(objPage2)
            Call objPage1.Children.Add(objBackground)
            Call objPage1.Children.Add(objPhoto)
            Call objPage1.Children.Add(objName)
            Call objPage2.Children.Add(objText)

            Return objLayout
        End Function

        Private Function GetImage(ByVal strName As String) As ImageSource
            Dim objStream As IO.Stream = Me.GetType().Assembly.GetManifestResourceStream("VisualBrushes." & strName & ".jpg")
            Dim objDecoder As New JpegBitmapDecoder(objStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad)

            Return objDecoder.Frames(0)
        End Function

        Private Sub UpdateLayoutPagePreviews()
            Call clnLayoutPagePreviews.Clear()

            For intLayoutPageIndex As Integer = 0 To m_objCurrentLayout.LayoutPages.Count - 1
                Dim objLayoutPage As cedLayoutPage = m_objCurrentLayout.LayoutPages(intLayoutPageIndex)
                Dim blnIsChecked As Boolean = (intLayoutPageIndex = m_objCurrentLayout.CurrentLayoutPageIndex)

                Call clnLayoutPagePreviews.Add(New cedLayoutPagePreview(intLayoutPageIndex, objLayoutPage, blnIsChecked))
            Next
        End Sub

    #End Region

    End Class

     

    cedLayout.vb

    Imports System.Collections.ObjectModel
    Imports System.Collections.Specialized
    Imports System.ComponentModel
    Imports System.IO
    Imports System.Windows.Markup
    Imports System.Xml

    <ContentProperty("LayoutPages")> Public Class cedLayout
        Inherits FrameworkElement

        ' Dependency properties
        Public Shared ReadOnly CurrentLayoutPageIndexProperty As DependencyProperty
        Public Shared ReadOnly LayoutPagesProperty As DependencyProperty

        ' Dependency-property keys
        Private Shared ReadOnly LayoutPagesPropertyKey As DependencyPropertyKey

        ' Internal fields
        Private m_clnVisualChildren As New Collection(Of Visual)

    #Region " Dependency properties "

        <Category("Card Template")> _
        Public Property CurrentLayoutPageIndex() As Integer
            Get
                Return CType(GetValue(CurrentLayoutPageIndexProperty), Integer)
            End Get
            Set(ByVal value As Integer)
                Call SetValue(CurrentLayoutPageIndexProperty, value)
            End Set
        End Property

        <Category("Card Template"), DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
        Public ReadOnly Property LayoutPages() As cedLayoutPageCollection
            Get
                Return CType(GetValue(LayoutPagesProperty), cedLayoutPageCollection)
            End Get
        End Property

    #End Region

    #Region " Constructors "

        Shared Sub New()
            Dim enmOptions As FrameworkPropertyMetadataOptions = FrameworkPropertyMetadataOptions.AffectsParentMeasure Or _
                                                                 FrameworkPropertyMetadataOptions.AffectsParentArrange Or _
                                                                 FrameworkPropertyMetadataOptions.AffectsMeasure Or _
                                                                 FrameworkPropertyMetadataOptions.AffectsArrange

            ' Determines what the current layout page is when in designing mode
            CurrentLayoutPageIndexProperty = DependencyProperty.Register("CurrentLayoutPageIndex", GetType(Integer), GetType(cedLayout), _
                New FrameworkPropertyMetadata(0, enmOptions))

            ' Determines the pages that make up this layout
            LayoutPagesPropertyKey = DependencyProperty.RegisterReadOnly("LayoutPages", GetType(cedLayoutPageCollection), GetType(cedLayout), _
                New FrameworkPropertyMetadata(New cedLayoutPageCollection, enmOptions))
            LayoutPagesProperty = LayoutPagesPropertyKey.DependencyProperty

        End Sub

        Public Sub New()
            Call MyBase.New()

            ' Create an empty layout-page collection
            Dim clnLayoutPages As New cedLayoutPageCollection

            ' Set the corresponding dependency property
            Call SetValue(LayoutPagesPropertyKey, clnLayoutPages)

            ' Attach the event handler that notifies any changes
            AddHandler clnLayoutPages.CollectionChanged, AddressOf CollectionChanged

        End Sub

    #End Region

    #Region " Collection event handlers "

        Private Sub CollectionChanged(ByVal sender As Object, ByVal e As NotifyCollectionChangedEventArgs)

            ' Update the logical tree
            If Not e.NewItems Is Nothing Then
                For Each objItem As Object In e.NewItems
                    Call AddLogicalChild(objItem)
                Next
            End If

            If Not e.OldItems Is Nothing Then
                For Each objItem As Object In e.OldItems
                    Call RemoveLogicalChild(objItem)
                Next
            End If

            ' Adding or removing layout pages requires the layout to be repainted
            Call InvalidateMeasure()

        End Sub

    #End Region

    #Region " Visual and logical-children override "

        Protected Overrides ReadOnly Property LogicalChildren() As System.Collections.IEnumerator
            Get
                Return LayoutPages.GetEnumerator
            End Get
        End Property

        Protected Overrides Function GetVisualChild(ByVal index As Integer) As Visual
            Return m_clnVisualChildren(index)
        End Function

        Protected Overrides ReadOnly Property VisualChildrenCount() As Integer
            Get
                Return m_clnVisualChildren.Count
            End Get
        End Property

        Private Sub AddVisual(ByVal objVisual As Visual)
            Call m_clnVisualChildren.Add(objVisual)
            Call MyBase.AddVisualChild(objVisual)
        End Sub

        Private Sub RemoveVisual(ByVal objVisual As Visual)
            Call m_clnVisualChildren.Remove(objVisual)
            Call MyBase.RemoveVisualChild(objVisual)
        End Sub

    #End Region

    #Region " Layout methods "

        Protected Overrides Function MeasureOverride(ByVal availableSize As System.Windows.Size) As System.Windows.Size

            ' Clear all visual children
            While m_clnVisualChildren.Count > 0
                Call RemoveVisual(m_clnVisualChildren(0))
            End While

            ' Add the current page to the visual children
            Call AddVisual(LayoutPages(CurrentLayoutPageIndex))

            ' Measure the child elements
            For Each objLayoutPage As cedLayoutPage In LayoutPages
                Call objLayoutPage.Measure(New Size(objLayoutPage.Width, objLayoutPage.Height))
            Next

            Return New Size(LayoutPages(CurrentLayoutPageIndex).Width, LayoutPages(CurrentLayoutPageIndex).Height)
        End Function

        Protected Overrides Function ArrangeOverride(ByVal finalSize As System.Windows.Size) As System.Windows.Size

            ' Position the child elements
            For Each objLayoutPage As cedLayoutPage In LayoutPages
                Call objLayoutPage.Arrange(New Rect(0, 0, objLayoutPage.Width, objLayoutPage.Height))
            Next

            Return finalSize
        End Function

    #End Region

    End Class

    Public Class cedLayoutCollection
        Inherits ObservableCollection(Of cedLayout)
    End Class

     

    cedLayoutPage.vb

    Imports System.Collections.ObjectModel
    Imports System.ComponentModel

    Public Class cedLayoutPage
        Inherits Canvas
    End Class

    Public Class cedLayoutPageCollection
        Inherits ObservableCollection(Of cedLayoutPage)
    End Class

     

    cedLayoutPagePreview.vb

    Imports System.Collections.ObjectModel

    Friend Class cedLayoutPagePreview
        Inherits DependencyObject

        ' Dependency properties
        Public Shared ReadOnly IndexProperty As DependencyProperty
        Public Shared ReadOnly IsCheckedProperty As DependencyProperty
        Public Shared ReadOnly LayoutPageProperty As DependencyProperty
        Public Shared ReadOnly ToolTipProperty As DependencyProperty

    #Region " Dependency properties "

        Public Property Index() As Integer
            Get
                Return CInt(GetValue(IndexProperty))
            End Get
            Set(ByVal value As Integer)
                Call SetValue(IndexProperty, value)
            End Set
        End Property

        Public Property IsChecked() As Boolean
            Get
                Return CBool(GetValue(IsCheckedProperty))
            End Get
            Set(ByVal value As Boolean)
                Call SetValue(IsCheckedProperty, value)
            End Set
        End Property

        Public Property LayoutPage() As cedLayoutPage
            Get
                Return CType(GetValue(LayoutPageProperty), cedLayoutPage)
            End Get
            Set(ByVal value As cedLayoutPage)
                Call SetValue(LayoutPageProperty, value)
            End Set
        End Property

        Public Property ToolTip() As String
            Get
                Return CStr(GetValue(TooltipProperty))
            End Get
            Set(value As String)
                Call SetValue(TooltipProperty, value)
            End Set
        End Property

    #End Region

    #Region " Other properties "

        Public ReadOnly Property PageNumber As Integer
            Get
                Return Index + 1
            End Get
        End Property

    #End Region

    #Region " Constructor "

        Shared Sub New()
            Dim enmOptions As FrameworkPropertyMetadataOptions = FrameworkPropertyMetadataOptions.AffectsParentMeasure Or _
                                                                 FrameworkPropertyMetadataOptions.AffectsParentArrange

            ' Determines the index of the layout page within the layout
            IndexProperty = DependencyProperty.Register("Index", GetType(Integer), GetType(cedLayoutPagePreview), _
                New FrameworkPropertyMetadata(0, enmOptions))

            ' Determines whether the layout page is currently selected
            IsCheckedProperty = DependencyProperty.Register("IsChecked", GetType(Boolean), GetType(cedLayoutPagePreview), _
                New FrameworkPropertyMetadata(False, enmOptions))

            ' Determines the layout-page object whose preview is being shown
            LayoutPageProperty = DependencyProperty.Register("LayoutPage", GetType(cedLayoutPage), GetType(cedLayoutPagePreview), _
                New FrameworkPropertyMetadata(Nothing, enmOptions))

            ' Deteremines the ToolTip of the layout-page preview
            TooltipProperty = DependencyProperty.Register("ToolTip", GetType(String), GetType(cedLayoutPagePreview), _
                New FrameworkPropertyMetadata(Nothing, enmOptions))

        End Sub

        Public Sub New(ByVal intIndex As Integer, ByVal objLayoutPage As cedLayoutPage)
            Index = intIndex
            LayoutPage = objLayoutPage
            ToolTip = GetToolTip()
        End Sub

        Public Sub New(ByVal intIndex As Integer, ByVal objLayoutPage As cedLayoutPage, ByVal blnIsChecked As Boolean)
            Index = intIndex
            IsChecked = blnIsChecked
            LayoutPage = objLayoutPage
            ToolTip = GetToolTip()
        End Sub

        Private Function GetToolTip() As String
            If Not (LayoutPage Is Nothing OrElse String.IsNullOrWhiteSpace(LayoutPage.Name)) Then
                Return LayoutPage.Name
            Else
                Return "[No Name]"
            End If
        End Function

    #End Region

    End Class

    Friend Class cedLayoutPagePreviewCollection
        Inherits ObservableCollection(Of cedLayoutPagePreview)
    End Class

     


    Rutger Koperdraad.
    Friday, June 03, 2011 11:44 PM
  • Hi Rutger Koperdraad,

    Thanks for the sample.

    Could you try the ListBox approach once you got some time? I think it can resolve the problem.

    The powerpoint also has a scrollbar for its content. If you don't like the scrollbar, you can use ScrollViewer.HorizontalScrollBarVisibility property to hide it. Then it could look exactly same as your current layout.

    Best regards,


    Min Zhu [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.


    Monday, June 06, 2011 9:37 AM
    Moderator
  • Hi Min Zhu,

    I actually managed to solve the problem. Unlike the sample, the layout pages did not have their Width and Height properties set explicitly in the real project. The reason for that was that the page size was implemented as a property of the parent object, while the pages could only differ in their protrait/landscape setting. Now, while measuring the parent object, I set the Width and Height properties of all pages explicitly and that solves the problem. It seams that visual brush did not know well what size of the original object was and got into trouble because of that.

    Thanks for your help!


    Rutger Koperdraad.
    • Marked as answer by cucucucu Monday, June 06, 2011 4:48 PM
    Monday, June 06, 2011 4:48 PM