我希望获得对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一样。 ;)
答案 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。