Winrt Hubsection中的参考控制

时间:2014-11-13 06:08:10

标签: c# winrt-xaml windows-8.1

我希望获得对WinRt集线器控件第一部分中的MediaElement的引用。人们会认为这是微不足道的,但到目前为止,它已经是一个完整的PITA。

我用Google搜索了问题并发现:

How do I access a control inside a XAML DataTemplate?

How to access any control inside Hubsection Datatemplate in Windows 8.1 store

但提供的代码不起作用。

我的(相关)Xaml如下:

 <Hub x:Name="MediaHub">
            <Hub.Header>
                <!-- Back button and page title -->
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="80"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    <Button  x:Name="backButton" Margin="-1,-1,39,0" Command="{Binding NavigationHelper.GoBackCommand, ElementName=pageRoot}"
                        Style="{StaticResource NavigationBackButtonNormalStyle}"
                        VerticalAlignment="Top"
                        AutomationProperties.Name="Back"
                        AutomationProperties.AutomationId="BackButton"
                        AutomationProperties.ItemType="Navigation Button"/>
                    <TextBlock x:Name="pageTitle" Text="{StaticResource AppName}" Style="{StaticResource HeaderTextBlockStyle}" Grid.Column="1" 
                        IsHitTestVisible="false" TextWrapping="NoWrap" VerticalAlignment="Top"/>
                </Grid>
            </Hub.Header>

            <HubSection Width="780" Margin="0,0,80,0">
                <HubSection.Background>
                    <ImageBrush Stretch="UniformToFill" />
                </HubSection.Background>
                <DataTemplate>
                    <Grid Margin="15">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="500"/>
                            <RowDefinition Height="*"/>
                        </Grid.RowDefinitions>

                        <MediaElement x:Name="videoElement1" AreTransportControlsEnabled="True"/>
                    </Grid>
                </DataTemplate>
            </HubSection>

以下实现的findname建议返回null:

private void navigationHelper_LoadState(object sender, LoadStateEventArgs e)
{
    this.videoElement = this.MediaHub.Sections[0].FindName("videoElement1") as MediaElement;

    if (this.videoElement != null)
    {
        this.videoElement.MediaOpened += VideoElementMediaOpened;
        this.videoElement.MediaFailed += VideoElementMediaFailed;
        this.videoElement.MarkerReached += VideoElementMarkerReached;
    }
}

VisualTree建议也返回null。

       private void navigationHelper_LoadState(object sender, LoadStateEventArgs e)
        {
            this.videoElement = this.FindChildControl<MediaElement>(this, "videoElement1") as MediaElement;

            if (this.videoElement != null)
            {
                this.videoElement.MediaOpened += VideoElementMediaOpened;
                this.videoElement.MediaFailed += VideoElementMediaFailed;
                this.videoElement.MarkerReached += VideoElementMarkerReached;
            }
        }


  private DependencyObject FindChildControl<T>(DependencyObject control, string ctrlName)
        {
            int childNumber = VisualTreeHelper.GetChildrenCount(control);
            for (int i = 0; i < childNumber; i++)
            {
                var child = VisualTreeHelper.GetChild(control, i);
                var fe = child as FrameworkElement;
                // Not a framework element or is null
                if (fe == null) return null;

                if (child is T && fe.Name == ctrlName)
                {
                    // Found the control so return
                    return child;
                }
                else
                {
                    // Not found it - search children
                    DependencyObject nextLevel = FindChildControl<T>(child, ctrlName);
                    if (nextLevel != null)
                        return nextLevel;
                }
            }
            return null;
        }

在这种情况下,找到MediaHub,但是当使用MediaHub作为“控制”参数递归输入函数FindChildControl时,

int childNumber = VisualTreeHelper.GetChildrenCount(control);

返回0的计数,因此它返回并向初始调用冒泡。虽然如果我设置了一个断点,我可以按照Xaml看到HubSections count=4。 (定义的部分比我输入的部分多,为简洁起见省略。)

经过反思,似乎我被迫使用基于Xaml的风格更像:

<MediaElement x:Name="videoElement1" AreTransportControlsEnabled="True" 
                                  MediaOpened="VideoElement1_OnMediaOpened"
                                  MediaFailed="VideoElement1_OnMediaFailed"
                                  MarkerReached="VideoElement1_OnMarkerReached"
                                  Source="{Binding SomeViewModelProperty}" />

我的问题是,我经常遇到使用Source= new Uri("xyz")静默失败的问题,但在代码中使用myMediaElement.SetSource(stream, file.ContentType)="xyz"可以在100%的时间内使用相同的源文件。因此,我想在代码中设置此源,因此需要参考。

因此,我不希望将此Xaml选项作为我问题的答案进行探讨,而是如何动态访问给定Hub的HubSection中的控件。在这一点上,我也想知道为了知道。

修改

根据Dani的回答,我尝试安装WinRt工具包并运行以下代码,但这也会返回null。

private void navigationHelper_LoadState(object sender, LoadStateEventArgs e) {
      var m = this.MediaHub.GetDescendantsOfType<MediaElement>().FirstOrDefault();
}

编辑2:

好的基本上归结为页面生命周期,我还没有读过很多,但是在Hub的Loaded事件中运行Danis代码和原始代码就是我们需要的。这样做和所有示例代码块都可以工作:

 public HubPage1()
        {
            this.InitializeComponent();
            this.navigationHelper = new NavigationHelper(this);
            this.navigationHelper.LoadState += navigationHelper_LoadState;
            this.MediaHub.Loaded += MediaHub_Loaded;

        }

        void MediaHub_Loaded(object sender, RoutedEventArgs e)
        {
            var m = this.MediaHub.GetDescendantsOfType<MediaElement>().FirstOrDefault();
            this.videoElement =
                this.FindChildControl<MediaElement>(this.MediaHub, "videoElement1") as
                    MediaElement;
        }

这就像WebForms一样。 ;)

2 个答案:

答案 0 :(得分:3)

这就是我的方式:

<Hub>
    <HubSection>
        <DataTemplate>
            <Button Loaded="MyButton_OnLoad" />
        </DataTemplate>
    </HubSection>    
</Hub>

然后这个:

private Button _MyButton = default(Button);
private void MyButton_OnLoad(object sender, RoutedEventArgs e)
{
    _MyButton = sender as Button;
}

然后这个:

void MainPage_Loaded(object sender, RoutedEventArgs e)
{
    this._MyButton.Visibility = Visibility.Visible;
}

这比通过VisualTree更好吗?也许。它更轻。

祝你好运!

答案 1 :(得分:2)

我已尝试使用WinRT XAML Toolkit中的VisualTreeHelperExtensions课程。

在那里,您可以致电this.MediaHub.GetDescendantsOfType<MediaElement>();,然后您就会获得videoElement1。