2016-06-22 78 views
2

我有一個訂單列表,當訂單狀態爲取消時,我想閃爍文本。到目前爲止,我的代碼工作。然而,有時會拋出異常:UWP與uWp中的FindAncestor等效函數

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> 

回答

0

在XAML 您可以嘗試使用的RelativeSource,它提供了一種手段來指定在運行時的相對關係而言綁定的源對象圖。 例如使用TemplatedParent

Height="{Binding RelativeSource={RelativeSource TemplatedParent}, 
      Path=Parent.ActualHeight} 

<Binding RelativeSource="{RelativeSource TemplatedParent}" ></Binding> 

在您嘗試使用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); 
    } 
} 

下面的示例顯示了檢查的元素的父

((StackPanel)LinePane.Parent).ActualWidth; 

同樣的代碼,這裏是不錯的展示這個課程的博客文章。 http://blog.jerrynixon.com/2012/09/how-to-access-named-control-inside-xaml.html

+0

嗨拉米,如何在xaml中應用VisualTreeHelper.GetParent?對不起,我是UWP的新手。 – Sam

+0

VisualTreeHelper類的用途是幫助您發現在對象的運行時樹中查找的對象,但沒有更直接的對象關係API可用於您的方案。有時候,你不會知道對象的確切類型或名稱。或者你也許知道一個特定的對象出現在樹的某個地方,但你不知道確切的位置。對於這些類型的場景,VisualTreeHelper很有幫助,因爲您可以遞歸地查找可視樹中的所有對象,然後查看該組並根據您的條件查找匹配項。 –

+0

@Sam希望以上是有幫助的。 –

0

我正在將應用程序從WPF轉換爲UWP,並發現此線程。看起來網上沒有好的解決方案,所以這裏是我嘗試通過解決方法'解決'這個問題。

注:下面是UWP UNTESTED(但在WPF作品)因爲我通過大量非編譯口部分的方式,但理論上它應該工作...

1創建一個RelativeSourceBinding附加屬性

該類有兩個屬性:AncestorType和Ancestor。當AncestorType發生變化時,我們訂閱FrameworkElement.Loaded(處理父更改)並查找類型的可視父項並分配給Ancestor附加屬性。

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是被定義爲

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看起來像這樣

<Style x:Key="SomeStyle" TargetType="local:AClass"> 
    <Style.Setters> 
     <Setter Property="SomeProperty" Value="{Binding Foo, RelativeSource={RelativeSource AncestorType=local:AnotherClass}}" /> 
    </Style.Setters> 
</Style> 

和後xaml

<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類型來查找的情況下,它應該可以工作。

+1

嗨,我會測試這個並報告回來。我沒有機會去研究它。再次感謝! – Sam

+0

有人可以確認此作品是否適用於UWP? – SuperJMN

1

考慮到我見過的所有解決方案,我覺得使用ElementName綁定是UWP沒有RelativeSource AncestorType綁定選項的最簡單的解決方法。

假設你已經得到了其DataContext設置爲與命令MyCommand一個視圖模型一個Page,並要在列表中執行它的每個項目被點擊的按鈕時:

<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的將是您的視圖模型(假設你的根元素太)

<Rectangle Name="VmDcHelper" Visibility="Collapsed"/> 

...然後在獨立的資源XAML文件,你可以寫你的DataTemplate這樣的:

<DataTemplate x:Key="MyDataTemplate"> 
    <Button Command="{Binding ElementName=VmDcHelper, Path=DataContext.MyCommand}" /> 
</DataTemplate> 

然後,在使用該模板資源的每個頁面/屏幕/對話框中,只需放入該矩形的副本(或其他任何內容),並且所有內容都將在運行時正確綁定

這顯然是一種黑客解決方案,但經過思考關於它更多,它不感覺就像再次使用WPF的AncestorType(必須確保您的祖先類型在您使用DataTemplate的所有位置始終保持一致)之間進行破解。