UWP与uwp中的FindAncestor等效

Sam*_*Sam 10 c# win-universal-app uwp windows-10-universal uwp-xaml

我有一个订单列表,当订单状态为Cancelled时,我想要闪烁文本.到目前为止,我的代码工作.但是,有时会抛出异常:

WinRT信息:无法解析TargetName lblOrderStatus

由于某种原因,可以找到lblOrderStatus.所以,我想使用"FindAncestor",但UWP中不存在FindAncestor.在uwp中是否有与FindAncestor等效的功能?

这是我的代码:

<ItemsControl x:Name="Orders" Grid.Row="1" Background="Transparent">
    ...
    ...
    ...
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Grid>
                ...
                ...
                ...
                <Viewbox Grid.Column="3" StretchDirection="DownOnly" HorizontalAlignment="Right">
                    <TextBlock x:Name="lblOrderStatus" Text="{Binding Path=OrderItemStatus, Mode=OneWay}" FontSize="18">
                        <TextBlock.Resources>
                            <Storyboard x:Name="sbBlinking">
                                <DoubleAnimation Storyboard.TargetProperty="(FrameworkElement.Opacity)"
                                                 Storyboard.TargetName="lblOrderStatus"
                                                 From="1" To="0" AutoReverse="True" Duration="0:0:0.5" RepeatBehavior="Forever" />
                            </Storyboard>
                        </TextBlock.Resources>
                        <interactive:Interaction.Behaviors>
                            <core:DataTriggerBehavior Binding="{Binding OrderItemStatus, Converter={StaticResource EnumToStringConverter}}" ComparisonCondition="Equal" Value="Cancelled">
                                <media:ControlStoryboardAction Storyboard="{StaticResource sbBlinking}" />
                            </core:DataTriggerBehavior>
                        </interactive:Interaction.Behaviors>
                    </TextBlock>
                </Viewbox>
            </Grid>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>
Run Code Online (Sandbox Code Playgroud)

BCA*_*BCA 12

考虑到我见过的所有解决方案,我觉得使用ElementName绑定是UWP最简单的解决方法,没有RelativeSource AncestorType绑定选项.

假设您已将PageDataContext设置为带有命令的viewmodel MyCommand,并且您希望列表中的每个项目在单击其按钮时执行它:

<Page Name="thisPage">
    ...
    <ListView ...>
        <ListView.ItemTemplate>
            <DataTemplate>
                <Button Command="{Binding ElementName=thisPage, Path=DataContext.MyCommand}" />
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</Page>
Run Code Online (Sandbox Code Playgroud)

我对此解决方案的初始问题是,您无法将DataTemplate作为资源提取出来,以便在多个屏幕(甚至是对话框)上使用它; thisPage可能不存在于每个位置,或者可能不适合将根元素命名为"thisPage".

但是如果你使用一个约定,你在每个使用该DataTemplate的屏幕中包含一个令牌UI元素,并通过一致的名称引用它,它将起作用.默认情况下,此元素的DataContext将是您的ViewModel(假设您的根元素也是如此)

<Rectangle Name="VmDcHelper" Visibility="Collapsed"/> 
Run Code Online (Sandbox Code Playgroud)

...然后在您的独立资源XAML文件中,您可以像这样编写DataTemplate:

<DataTemplate x:Key="MyDataTemplate">
    <Button Command="{Binding ElementName=VmDcHelper, Path=DataContext.MyCommand}" />
</DataTemplate>
Run Code Online (Sandbox Code Playgroud)

然后,在您使用该模板资源的每个页面/屏幕/对话框上,只需放入该Rectangle(或其他)的副本,一切都将在运行时正确绑定

这显然是一个黑客攻击解决方案,但是在考虑了它之后,它首先感觉不再像使用WPF的AncestorType那样黑客攻击了(必须确保你的祖先类型在所有地方始终保持一致)使用您的DataTemplate).


Ram*_*ine 0

在XAML中, 您可以尝试使用RelativeSource,它提供了一种根据运行时对象图中的相对关系指定绑定源的方法。例如使用TemplatedParent

Height="{Binding RelativeSource={RelativeSource TemplatedParent}, 
          Path=Parent.ActualHeight}
Run Code Online (Sandbox Code Playgroud)

或者

<Binding RelativeSource="{RelativeSource TemplatedParent}" ></Binding>
Run Code Online (Sandbox Code Playgroud)

在代码中,您尝试使用 VisualTreeHelper.GetParent 方法。 https://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.media.visualtreehelper.getparent

类似于下面的内容,这是一个实用函数的示例

internal static void FindChildren<T>(List<T> results, DependencyObject startNode)
  where T : DependencyObject
{
    int count = VisualTreeHelper.GetChildrenCount(startNode);
    for (int i = 0; i < count; i++)
    {
        DependencyObject current = VisualTreeHelper.GetChild(startNode, i);
        if ((current.GetType()).Equals(typeof(T)) || (current.GetType().GetTypeInfo().IsSubclassOf(typeof(T))))
        {
            T asType = (T)current;
            results.Add(asType);
        }
        FindChildren<T>(results, current);
    }
}
Run Code Online (Sandbox Code Playgroud)

以下示例显示了检查元素的父元素的代码

((StackPanel)LinePane.Parent).ActualWidth;
Run Code Online (Sandbox Code Playgroud)

另外,这里有一篇很好的博客文章,展示了此类的实际应用。http://blog.jerrynixon.com/2012/09/how-to-access-named-control-inside-xaml.html