首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >UWP中与FindAncestor的等价函数

UWP中与FindAncestor的等价函数
EN

Stack Overflow用户
提问于 2016-06-22 15:52:23
回答 3查看 6.2K关注 0票数 12

我有一个订单列表,当订单状态被取消时,我想要闪烁文本。到目前为止,我的代码起作用了。但是,有时会抛出异常:

WinRT信息:无法解析TargetName lblOrderStatus

由于某些原因,可以找到lblOrderStatus。所以,我想使用" FindAncestor ",但是FindAncestor并不存在于UWP中。在uwp中有与FindAncestor等效的函数吗?

这是我的代码:

代码语言:javascript
复制
<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>
EN

回答 3

Stack Overflow用户

发布于 2017-12-02 18:38:02

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

假设Page将其DataContext设置为具有命令MyCommand的视图模型,并且希望在单击其按钮时执行列表中的每一项:

代码语言:javascript
复制
<Page Name="thisPage">
    ...
    <ListView ...>
        <ListView.ItemTemplate>
            <DataTemplate>
                <Button Command="{Binding ElementName=thisPage, Path=DataContext.MyCommand}" />
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</Page>

这个解决方案的最初问题是,您不能将DataTemplate提取出来作为在多个屏幕(甚至对话框)上使用它的资源;thisPage可能不存在于每个地方,或者可能不适合将根元素命名为"thisPage“。

但是,如果您使用的约定是在每个使用该DataTemplate的屏幕中都包含一个令牌UI元素,并以一致的名称引用它,它就会工作。默认情况下,这个元素的DataContext将是您的ViewModel (假设根元素也是这样)

代码语言:javascript
复制
<Rectangle Name="VmDcHelper" Visibility="Collapsed"/> 

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

代码语言:javascript
复制
<DataTemplate x:Key="MyDataTemplate">
    <Button Command="{Binding ElementName=VmDcHelper, Path=DataContext.MyCommand}" />
</DataTemplate>

然后,在您使用该模板资源的每个页面/屏幕/对话框上,只需放入该矩形(或其他什么)的副本,所有内容都将在运行时正确绑定。

这显然是一种黑客解决方案,但经过更多的思考之后,它并不比使用WPF的AncestorType更像是黑客(必须确保您的祖先类型在所有使用DataTemplate的地方都是一致的)。

票数 17
EN

Stack Overflow用户

发布于 2017-04-13 18:14:37

我正在将一个应用程序从WPF转换到UWP,并找到了这个线程。网络上似乎没有好的解决方案,所以我试图通过解决这个问题来“解决”这个问题。

注意:下面是UWP中的未测试的(但在WPF中工作),因为我通过一个大型的非编译端口,但是理论上它应该能工作.

1创建RelativeSourceBinding附加属性

这个类有两个属性: AncestorType和祖先。当AncestorType更改时,我们订阅FrameworkElement.Loaded (以处理父更改),并找到类型的可视父级并将其分配给祖先附加属性。

代码语言:javascript
复制
public class RelativeSourceBinding
{
    public static readonly DependencyProperty AncestorTypeProperty = DependencyProperty.RegisterAttached("AncestorType", typeof(Type), typeof(RelativeSourceBinding), new PropertyMetadata(default(Type), OnAncestorTypeChanged));

    public static void SetAncestorType(DependencyObject element, Type value)
    {
        element.SetValue(AncestorTypeProperty, value);
    }

    public static Type GetAncestorType(DependencyObject element)
    {
        return (Type)element.GetValue(AncestorTypeProperty);
    }

    private static void OnAncestorTypeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ((FrameworkElement)d).Loaded -= OnFrameworkElementLoaded;

        if (e.NewValue != null)
        {
            ((FrameworkElement)d).Loaded += OnFrameworkElementLoaded;
            OnFrameworkElementLoaded((FrameworkElement) d, null);
        }
    }

    private static void OnFrameworkElementLoaded(object sender, RoutedEventArgs e)
    {
        var ancestorType = GetAncestorType((FrameworkElement) sender);
        if (ancestorType != null)
        {
            var findAncestor = ((FrameworkElement) sender).FindVisualParent(ancestorType);
            RelativeSourceBinding.SetAncestor(((FrameworkElement)sender), findAncestor);
        }
        else
        {
            RelativeSourceBinding.SetAncestor(((FrameworkElement)sender), null);
        }
    }

    public static readonly DependencyProperty AncestorProperty = DependencyProperty.RegisterAttached("Ancestor", typeof(UIElement), typeof(RelativeSourceBinding), new PropertyMetadata(default(FrameworkElement)));

    public static void SetAncestor(DependencyObject element, UIElement value)
    {
        element.SetValue(AncestorProperty, value);
    }

    public static UIElement GetAncestor(DependencyObject element)
    {
        return (UIElement)element.GetValue(AncestorProperty);
    }
}

其中,FindVisualParent是定义为

代码语言:javascript
复制
public static UIElement FindVisualParent(this UIElement element, Type type) 
{
    UIElement parent = element;
    while (parent != null)
    {
        if (type.IsAssignableFrom(parent.GetType()))
        {
            return parent;
        }
        parent = VisualTreeHelper.GetParent(parent) as UIElement;
    }
    return null;
}

2在XAML中应用RelativeSourceBinding属性

在WPF中使用xaml之前的一些示例如下所示

代码语言:javascript
复制
<Style x:Key="SomeStyle" TargetType="local:AClass">
    <Style.Setters>
        <Setter Property="SomeProperty" Value="{Binding Foo, RelativeSource={RelativeSource AncestorType=local:AnotherClass}}" />
    </Style.Setters>
</Style>

以及xaml之后

代码语言:javascript
复制
<Style x:Key="SomeStyle" TargetType="local:AClass">
    <Style.Setters>
        <Setter Property="apc:RelativeSourceBinding.AncestorType" Value="local:AnotherClass"/>
        <Setter Property="Foreground" Value="{Binding Path=(apc:RelativeSourceBinding.Ancestor).Foo, RelativeSource={RelativeSource Self}}" />
    </Style.Setters>
</Style>

这有点麻烦,但如果您只有一种RelativeSource FindAncestor类型可供查找,则应该可以使用。

票数 2
EN

Stack Overflow用户

发布于 2016-06-25 18:44:53

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

代码语言:javascript
复制
Height="{Binding RelativeSource={RelativeSource TemplatedParent}, 
          Path=Parent.ActualHeight}

代码语言:javascript
复制
<Binding RelativeSource="{RelativeSource TemplatedParent}" ></Binding>

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

如下所示,下面是实用程序函数的示例

代码语言:javascript
复制
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);
    }
}

下面的示例显示检查元素父级的代码

代码语言:javascript
复制
((StackPanel)LinePane.Parent).ActualWidth;

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37972934

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档