7

是的,所以我正在关注一个教程。这个,准确的说。它提供的一些代码是这样的:

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

如您所见,它绑定到 aTextBox的验证错误,即TextBoxis 。现在,我的问题是:我有点像这个。它也只有一个。但是,如果可能的话,我宁愿不使用s 或s 。是否可以在不命名该控件的情况下绑定到另一个控件,并且该控件是该控件中唯一的一个?与处于同一水平。x:NameAddressBoxWindowTextBoxNamex:NameControlValidation.ErrorsControlWindowTextBoxListBox

4

3 回答 3

5

除了与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 进行遍历的方法。我已将此方法放在我的实用程序类中,在许多情况下都很方便 -

    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;
    }
于 2013-08-20T12:47:12.193 回答
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>

第一个Bindingwith从视图中RelativeSource找到视图模型 ( DataContext)。ImageButton.IsEnabled属性为真时,第二个会淡出。此外,您可以将第二部分放入样式中,并ImageButton.Content属性中有任何内容时重用它,而无需声明任何名称。

您可以从MSDN 上的RelativeSource MarkupExtension页面了解更多信息。

于 2013-08-06T13:27:39.360 回答
0

我相信您唯一的其他选择是定义一个自定义标记扩展来满足您的要求。例如,您可以定义一个扩展,从名称范围的根元素中查找特定标记类型的第一个元素。在下面的链接中查找扩展部分作为起点。

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

此外,您还可以查看以下链接底部附近的示例。

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

我的回答是说我从未实施过,所以可能会有特定的限制阻碍你尝试做的事情。

于 2013-08-06T14:31:07.530 回答