Nicke Manarin
Nicke Manarin

Reputation: 3358

How to access template of element

I have a Control with a ScrollViewer inside its ControlTemplate (inside the Style), I want to access that ScrollViewer to work together with a ScrollSynchronizer.

http://www.codeproject.com/Articles/39244/Scroll-Synchronization

Here's the Style of the control:

<!--ZoomControl-->
<Style TargetType="{x:Type local:ZoomBox}">
    <Setter Property="ClipToBounds" Value="True"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:ZoomBox}">
                <ScrollViewer x:Name="ScrollViewer" ClipToBounds="True"
                              Background="Transparent" SnapsToDevicePixels="True" 
                              UseLayoutRounding="True"
                              VerticalScrollBarVisibility="Auto" 
                              HorizontalScrollBarVisibility="Auto" >
                    <Grid x:Name="Grid" RenderTransformOrigin="0.5,0.5" 
                          Background="Transparent" HorizontalAlignment="Center" 
                          VerticalAlignment="Center" SnapsToDevicePixels="True" 
                          UseLayoutRounding="True">
                        <Grid.LayoutTransform>
                            <TransformGroup>
                                <ScaleTransform x:Name="ScaleTransform"/>
                            </TransformGroup>
                        </Grid.LayoutTransform>
                        <Viewbox Grid.Column="0" Grid.Row="0" SnapsToDevicePixels="True" 
                                 UseLayoutRounding="True">
                            <Image Name="ImageCtrl" Source="{TemplateBinding ImageSource, 
                                   Converter={StaticResource UriToBitmapConverter}}" 
                                   SnapsToDevicePixels="True" UseLayoutRounding="True"/>
                        </Viewbox>
                    </Grid>
                </ScrollViewer>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

I'm trying to do this:

private static void OnScrollGroupChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var scrollViewer = d as ScrollViewer;

    if (scrollViewer == null && d.GetType() == typeof (ZoomBox))
    {
        //FindResource always returns null.
        scrollViewer = (ScrollViewer)(d as ZoomBox).FindResource("ScrollViewer");
    }
    //...
}

I also tried to create a public Getter inside the custom control:

public ScrollViewer GetScrollViewer()
{
    return Template.FindName("ScrollViewer", this) as ScrollViewer;
}

This same code works when inside the OnApplyTemplate() method. But on this case, Resources is null or empty.

Edit:

The ScrollSynchronization class works while grouping ScrollViewer elements using a AttachedProperty:

<n:ZoomBox x:Name="ZoomBoxControl" util:ScrollSynchronizer.ScrollGroup="Group1"/>

<ScrollViewer x:Name="SideScrollViewer" util:ScrollSynchronizer.ScrollGroup="Group1"/>

So, the maybe the Zoombox element is not even initialized before the OnScrollGroupChanged fired. That may explain why the Resource is always empty.

Edit 2:

One possible solution may be set the AttachedProperty after the window loading via code.

Edit 3:

This code works, it runs at the Window_OnLoaded event, I just wish I could use xaml to attach the properties.

ScrollSynchronizer.SetScrollGroup(ZoomBoxControl.GetScrollViewer(), "Canvas");
ScrollSynchronizer.SetScrollGroup(MainScrollViewer, "Canvas");

I looked at the Visual Tree after the OnGroupChanged was called and it looks like the AttachedProperty is resolved as soon as the ZoomBox element is interpreted, but before its initialization. So there is no Template loaded yet.

Upvotes: 0

Views: 72

Answers (1)

Szabolcs D&#233;zsi
Szabolcs D&#233;zsi

Reputation: 8843

If I understand correctly you are writing a custom control, so you have a class somewhere deriving from Control or a FrameworkElement-derived class:

Just tested and this works perfectly for me:

[TemplatePart(Name = "ScrollViewer", Type = typeof(ScrollViewer))]
public class ZoomBox : Control
{
    private ScrollViewer _scrollViewerPart;

    public override void OnApplyTemplate()
    {
        _scrollViewerPart = GetTemplateChild("ScrollViewer") as ScrollViewer;
    }

    public ScrollViewer GetScrollViewer()
    {
        return _scrollViewerPart;
    }
}

As the MSDN article writes about OnApplyTemplate:

Derived classes of FrameworkElement can use this method as a notification for a variety of possible scenarios:

  • You can run code that relies on the visual tree from templates having been applied, such as obtaining references to named elements that came from a template.

Upvotes: 1

Related Questions