2013-08-06 91 views
2

對,所以我正在學習一個教程。準確地說,是This one。它提供了一些代碼是這樣的:如何綁定到沒有名稱或x:名稱的控件?

<TextBlock Margin="2" Foreground="Red" FontWeight="Bold" 
      Text="{Binding ElementName=AddressBox, 
      Path=(Validation.Errors), 
      Converter={StaticResource eToMConverter}}" /> 

正如你所看到的,它綁定到一個TextBox的驗證錯誤,這TextBoxx:NameAddressBox。現在,我的問題是:我有一個Window有點像這個。它也只有一個TextBox。但是,如果可能的話,我寧願不使用Namex:Name。是否有可能綁定到另一個ControlValidation.Errors而沒有命名該控件,並且該控件是該Control上同一Window中唯一的一個? TextBoxListBox處於同一水平。

+2

我會說使用'x:Name',因爲您可能想出的任何其他解決方案都會更復雜且效率更低。 –

+0

@Sniffer我很感興趣,看看是否有其他選擇。 –

回答

2

除了與ElementName綁定之外,其他方式使用的是x:Reference,但它也需要目標元素在其上定義x:Name。所以,這裏超出了範圍。

其他方法沒有定義名稱我可以想到的是綁定類似下面的東西(綁定到父項和索引器以獲得目標子項)。

但這是緊耦合到您的邏輯樹結構 -

<StackPanel> 
     <TextBlock Text="Test"/> 
     <TextBlock Text="{Binding Parent.Children[0].Text, 
          RelativeSource={RelativeSource Mode=Self}}"/> 
    </StackPanel> 

而且,這可以使用IValueConverter實現。正如你所提到的那樣,父容器中只有一個這樣的元素,你可以將一個父元素傳遞給使用VisualTreeHelper類的子元素。

 <StackPanel> 
     <TextBlock Text="Test"/> 
     <TextBlock Text="{Binding Parent, RelativeSource={RelativeSource Self}, 
        Converter={StaticResource MyConverter}}"/> 
    </StackPanel> 

這是你的轉換器代碼 -

public class MyConverter: IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, 
          System.Globalization.CultureInfo culture) 
    { 
     if (value is DependencyObject) 
     { 
      var textBlock = FindChild<TextBlock>((DependencyObject)value, null); 
      return (textBlock == null)?string.Empty:textBlock.Text; 
     } 
     else 
      return String.Empty; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, 
            System.Globalization.CultureInfo culture) 
    { 
     return Binding.DoNothing; 
    } 
} 

下面是使用VisualTreeHelper遍歷方法。我把這種方法放在我的Utility類中,在很多情況下很方便 -

public static T FindChild<T>(DependencyObject parent, string childName) 
     where T : DependencyObject 
    { 
     // Confirm parent is valid. 
     if (parent == null) return null; 

     T foundChild = null; 

     int childrenCount = VisualTreeHelper.GetChildrenCount(parent); 
     for (int i = 0; i < childrenCount; i++) 
     { 
      var child = VisualTreeHelper.GetChild(parent, i); 
      // If the child is not of the request child type child 
      T childType = child as T; 
      if (childType == null) 
      { 
       // recursively drill down the tree 
       foundChild = FindChild<T>(child, childName); 

       // If the child is found, break so we do not 
       // overwrite the found child. 
       if (foundChild != null) break; 
      } 
      else if (!string.IsNullOrEmpty(childName)) 
      { 
       var frameworkElement = child as FrameworkElement; 
       // If the child's name is set for search 
       if (frameworkElement != null 
        && frameworkElement.Name == childName) 
       { 
        // if the child's name is of the request name 
        foundChild = (T)child; 
        break; 
       } 
      } 
      else 
      { 
       // child element found. 
       foundChild = (T)child; 
       break; 
      } 
     } 

     return foundChild; 
    } 
+0

哇,很酷。現在,如果你能從控制中獲得兒童指數,這將是完美的。可以做到嗎? –

+0

是的,我們可以得到索引。另外,我已經使用VisualTreeHelper的另一種方法進行了更新。 –

+0

@ It'sNotALie - 它是否解決了您的問題,或者您還在尋找其他可行的解決方案? –

0

您還可以使用RelativeSource連接到另一個非命名控制如果控制是控制與結合父:

<Button Command="{Binding DataContext.ACommand, RelativeSource={RelativeSource 
    FindAncestor, AncestorType={x:Type Views:AView}}}" Margin="0,2,0,2"> 
    <Image Source="{Binding AnImage}"> 
     <Image.Style> 
      <Style TargetType="{x:Type Image}"> 
       <Setter Property="Width" Value="16" /> 
       <Setter Property="Height" Value="16" /> 
       <Setter Property="Opacity" Value="1.0" /> 
       <Style.Triggers> 
        <DataTrigger Binding="{Binding IsEnabled, RelativeSource={ 
         RelativeSource FindAncestor, AncestorType={x:Type Button}}, 
         FallbackValue=False}" Value="False"> 
         <Setter Property="Opacity" Value="0.5" /> 
        </DataTrigger> 
       </Style.Triggers> 
      </Style> 
     </Image.Style> 
    </Image> 
</Button> 

第一BindingRelativeSource發現視圖模型(DataContext )從視圖。當Button.IsEnabled屬性爲真時,第二個會淡化Image。此外,您可以將此第二部分放入一個樣式中,並在Button.Content屬性中有任何Image而無需聲明任何名稱時重新使用它。

您可以在MSDN的RelativeSource MarkupExtension頁面找到更多信息。

+0

這不是一個祖先,不幸的是,它們都在同一個「網格」內。感謝你說明這一點,可能有一些非常奇怪的方式來使用這與附加屬性。 –

0

我相信你唯一的選擇就是定義一個自定義標記擴展,它可以滿足你的要求。作爲一個例子,你可以定義一個擴展名,從namescope的根元素中找到某個標籤類型的第一個元素。以下面鏈接中的擴展部分爲起點。

http://msdn.microsoft.com/en-us/library/ms747254.aspx

同樣爲例,你可以看看附近以下鏈接的底部。

http://www.codeproject.com/Articles/140618/WPF-Tutorial-TypeConverter-Markup-Extension

我有資格跟我說,我從來沒有實現一個這樣有可能會在你正在嘗試做的方式,得到具體的響應限制。