jeffora
jeffora

Reputation: 4169

Setting a Control in a DataTemplate as the CommandTarget of a Button outside the template

I am working on a project that involves playing TV from a tuner card in a WPF application. Recently, I have been rewriting the TV playback capabilities to work with WPF MediaKit to allow for a more seamless interaction experience (previously I was using WindowsFormsHost and a WinForms control as the DirectShow render target, resulting in all the usual air space issues).

The software plays both analog and digital TV, and as they are handled differently, I've created a Player and MediaElement for both (DigitalTvPlayer, DigitalTvElement, AnalogTvPlayer, AnalogTvElement), extending from the respective MediaKit classes MediaPlayerBase and MediaElementBase.

These controls are all working, but I am now looking for a way to have a single 'TV Player Window' that can contain a list of channels (a mix of analog and digital) and automatically handle switching between them, selecting the appropriate player.

My first attempt at doing this involved using a ContentPresenter bound to the selected channel, and a specific DataTemplate for each channel type:

<Window.Resources>
    <DataTemplate DataType="{x:Type Channels:AnalogChannel}">
        <Controls:AnalogTvGraphFileElement
            AnalogSpecificData="..."
            Channel="{Binding}" />
    </DataTemplate>
    <DataTemplate DataType="{x:Type Channels:DigitalChannel}">
        <Controls:DigitalTvElement
            DigitalSpecificData="..."
            Channel="{Binding}" />
    </DataTemplate>
</Window.Resources>

With the following window body:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="Auto" />
    </Grid.ColumnDefinitions>
    <ContentPresenter 
        x:Name="TvPresenter" 
        VerticalAlignment="Stretch" 
        HorizontalAlignment="Center" 
        Content="{Binding ElementName=TvChannels, Path=SelectedItem}" />

    <ListBox Grid.Column="1" x:Name="TvChannels" ItemsSource="{Binding Channels}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding}" />
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>

Although this approach 'works' (TV plays, it automatically switches between analog and digital etc), I lose the ability to have direct control of the TvElements, such as targeting them for commands such as MediaCommands.Play, as I only have a reference to the ContentPresenter or its bound Channel object.

Ideally, I'd like to be able to set one of these TvPlayers as the CommandTarget of a Button (that will likely be outside the DataTemplate). However, I'm not sure how to go about doing that (or whether that is even a good idea - it feels hackish and error-prone to search a DataTemplate looking for a specific control).

I feel like I'm missing something or going about this the wrong way. Does anyone have any advice or suggestions on how I can achieve a generic (preferably declarative) means of handling channels, without losing the ability to execute commands on the player?

Upvotes: 1

Views: 416

Answers (1)

Arcturus
Arcturus

Reputation: 27065

You could try to use the Loaded event to set a field in your code behind.

<Window.Resources>
    <DataTemplate DataType="{x:Type Channels:AnalogChannel}">
        <Controls:AnalogTvGraphFileElement
            AnalogSpecificData="..." Loaded="OnAnalogTvGraphFileElementLoaded"                Channel="{Binding}" />
    </DataTemplate>
    <DataTemplate DataType="{x:Type Channels:DigitalChannel}">
        <Controls:DigitalTvElement
            DigitalSpecificData="..." Loaded="OnDigitalTvElementLoaded"
            Channel="{Binding}" />
    </DataTemplate>
</Window.Resources>

and the loaded methods will set your field in code behind:

private AnalogTvGraphFileElement analogFileElement;

private void OnAnalogTvGraphFileElementLoaded(object sender, RoutedEventArgs e)
{
    analogFileElement = (AnalogTvGraphFileElement) sender;
}

So when needed, you will have the correct controls, and won't have to look for them first.

Upvotes: 1

Related Questions