WPF中的x:Reference何时被解析,为什么XAML元素的顺序会影响它?

11

我重新排列XAML元素后,x:Reference无法解析。

这里有一段可用的代码。只需将DataGrid元素移动到按钮元素之后,ContextMenu中MenuItem的绑定和Button.IsEnabled中的MultiBinding就会失效。在Button.IsEnabled中,仅MultiBinding会失效。可以用注释块替换它,并且x:Reference在该单个绑定中有效。

两者都会抛出XamlParseException异常。

  • MenuItem会出现System.Xaml.XamlObjectWriterException异常,消息中涉及未解决的引用。
  • MultiBinding会抛出System.Collections.Generic.KeyNotFoundException异常作为内部异常。

那么,x:Reference实际上何时解析?为什么仅当被引用的元素在引用它的元素之后时才会破坏某些绑定?

下面是我的XAML:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:xxx="clr-namespace:WpfApplication1"
        Title="MainWindow" SizeToContent="WidthAndHeight">
    <Window.Resources>
        <xxx:BoolToVisibleConverter x:Key="boolToVisibleConv"></xxx:BoolToVisibleConverter>
        <xxx:NullToFalseConverter x:Key="nullToFalseConv"></xxx:NullToFalseConverter>
        <xxx:NullsOrToFalseConverter x:Key="nullsOrToFalseConv"></xxx:NullsOrToFalseConverter>
        <ContextMenu x:Key="MyMenu">
            <MenuItem 
                Header="Menuitem enabled when row selected" 
                IsEnabled="{Binding 
                    Path=SelectedItem, 
                    Source={x:Reference dataGridElement}, 
                    Converter={StaticResource nullToFalseConv}}" />
        </ContextMenu>
    </Window.Resources>
    <StackPanel>
        <DataGrid 
            Name="dataGridElement" 
            IsReadOnly="True" />
        <Button 
            Content="Button" 
            ContextMenu="{StaticResource MyMenu}" 
            Visibility="{Binding 
                Path=IsReadOnly, 
                Source={x:Reference dataGridElement},
                Converter={StaticResource boolToVisibleConv}}">
            <Button.IsEnabled>
                <!--<Binding 
                    Path="SelectedItem" 
                    Source="{x:Reference dataGridElement}" 
                    Converter="{StaticResource nullToFalseConv}"/>-->
                <MultiBinding 
                    Converter="{StaticResource nullsOrToFalseConv}">
                    <Binding 
                        Path="SelectedItem" 
                        Source="{x:Reference dataGridElement}"/>
                    <Binding 
                        Path="SelectedItem" 
                        Source="{x:Reference dataGridElement}"/>
                </MultiBinding>
            </Button.IsEnabled>
        </Button>
    </StackPanel>
</Window>

这是我的代码后端(不包含using语句):

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
    public class BoolToVisibleConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value == null || (bool)value == false)
                return System.Windows.Visibility.Hidden;
            else
                return System.Windows.Visibility.Visible;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    public class NullsOrToFalseConverter : IMultiValueConverter
    {
        public object Convert(object[] value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            foreach (object val in value)
            {
                if (val == null)
                    return false;
            }
            return true;
        }

        public object[] ConvertBack(object value, Type[] targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    public class NullToFalseConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return (value != null);
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}
3个回答

2
我想这是因为您的资源(Window.Resources)将在引用实例存在之前先被创建。我建议通过数据上下文(ViewModel)来解决这个问题。
<Window.DataContext>
        <yourNameSpace:YourViewModel x:Name="VieModName" />
    </Window.DataContext>
<MenuItem Header="HeadrTxt" Command="{Binding CommandInViewModelCmd}" DataContext="{x:Reference Name=VieModName}" />

0

摘自 MSDN(http://msdn.microsoft.com/en-us/library/ee795380.aspx)。

x:Reference 是 XAML 2009 中定义的一个结构。在 WPF 中,您可以使用 XAML 2009 功能,但仅限于非 WPF 标记编译的 XAML。标记编译 XAML 和 XAML 的 BAML 形式目前不支持 XAML 2009 语言关键字和功能。


-1

x:Reference 在 WPF 中必须避免使用。因为这个标记扩展是 XAML 语言的最近添加(2009年)。并且在 WPF 中不完全支持。在你的 Binding 中使用 ElementName 而不是 x:Reference

<Binding Path="SelectedItem" 
         ElementName="dataGridElement"/>

MSDN上。


1
问题在于有时ElementName找不到元素。这就是我最初使用x:Reference的原因。据我所知,当ElementName无法工作时,x:Reference是一种解决方法。那么如果它们都不起作用怎么办?例如,在此情况下,使用ElementName可以使Button.IsEnabled中的MultiBinding正常工作,但无法启用上下文菜单项。 - user2032138
@user2032138 这在MSDN文章中有解释,"但仅适用于非WPF标记编译的XAML。" - Cédric Bignon
1
那么在这种情况下,当XAML描述应用程序的主要用户界面时,不支持使用x:Reference吗? - user2032138
@user2032138 我从未使用过它。但在大多数情况下,它是无用的,可以被 ElementName 替代。 - Cédric Bignon
3
@Cédric Bignon,在特定情况下,ElementName 不起作用,而对于 .NET 4 或更高版本,_{x:Reference}_ 是一个很好的解决方法。具体来说,在尝试从 DataGridTemplateColumn 中进行绑定时,由于 WPF 树中存在问题,ElementName 会失败,尽管在我的经验中,它只影响 Windows XP。请参阅 此 stackoverflow 问题这个问题 - Andrew B

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接