Access XAML Control In DataTemplate From CodeBehin

2019-03-01 00:13发布

问题:

I have a control that I am unable to access in the codebehind, and I believe it is because it is defined in a DataTempalte.

The overall control is a slide show carousel. Each slide can be an Image or a MediaElement (video), the contents of which are defined in an ItemSource binding. The carousel is on a timer to switch from one slide to the next. Each time the slide changes I fire an event to that effect.

When I hit a slide with a video I'd like to stop the slide timer (done that) and start the video, which is where I've run into a problem. I can not access the MediaPlayer element Name from my codebehind. My assumption at this point is because it is a DataTemplate.

Is this assumption correct? If so, how can I get access to this control from the codebehind, or (more to the point) have it start playing when the slide comes up?

<ctrl:AutoScrollCarousel ...>
    <ctrl:AutoScrollCarousel.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal" />
        </ItemsPanelTemplate>
    </ctrl:AutoScrollCarousel.ItemsPanel>
    <ctrl:AutoScrollCarousel.ItemTemplate>
        <DataTemplate>
            <Border x:Name="Border" VerticalAlignment="Center"
                    Width="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType={x:Type UserControl},Mode=FindAncestor}}">
                <Grid Background="White">
                    ...
                    <Image Source="{Binding ContentImage}" Grid.Row="1" Grid.Column="1" Stretch="UniformToFill"
                            HorizontalAlignment="Center"
                            Visibility="{Binding ContentImage, Converter={StaticResource VisibilityConverter}}" />

                    <MediaElement Name="MediaPlayer" Source="{Binding ContentVideo}" Grid.Row="1" Grid.Column="1" Stretch="UniformToFill" LoadedBehavior="Play"
                                    Visibility="{Binding ContentVideo, Converter={StaticResource VisibilityConverter}}" MediaEnded="MediaPlayer_MediaEnded" />

                    <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Title}" Foreground="Black"
                                FontFamily="Segoe UI" FontWeight="Light" HorizontalAlignment="Left" FontSize="75" Margin="0" VerticalAlignment="Center" />

                    <TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding ContentHeadline}" Foreground="Black"
                                FontFamily="Segoe UI" FontWeight="Light" HorizontalAlignment="Left" FontSize="50" VerticalAlignment="Center"
                                TextWrapping="Wrap">
                    </TextBlock>
                </Grid>
            </Border>
        </DataTemplate>
    </ctrl:AutoScrollCarousel.ItemTemplate>
</ctrl:AutoScrollCarousel>

回答1:

I would normally recommend not to touch UIElements from code... but the MediaElement is a special case... maybe you should wrap the whole template inside a usercontrol (maybe with some custom DepProps) and that will give you better control over the whole thing.

Edit: Another approach would be to create a Behavior with a couple of properties (such as IsPlaying) and manipulate the mediaelement from there. Then you could use this behavior in the XAML of the DataTemplate, with no need for code behind or usercontrols.



回答2:

WPF provides a simple and straightforward way to access named elements that are generated from DataTemplates. It is explained in the MSDN article How to: Find DataTemplate-Generated Elements.

Assumed that your AutoScrollCarousel is derived from ItemsControl, you would get the ContentPresenter that is the container of an item like this:

AutoScrollCarousel carousel = ...
object item = ...
var contentPresenter =
    carousel.ItemContainerGenerator.ContainerFromItem(item) as ContentPresenter;

From the ContentPresenter you would get the named element in the DataTemplate by means of the FindName method:

var dataTemplate = contentPresenter.ContentTemplate;
var mediaPlayer = dataTemplate.FindName("MediaPlayer", contentPresenter) as MediaElement;