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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14644924/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 07:20:32  来源:igfitidea点击:

When is x:Reference in WPF resolved and why does XAML element order affect it?

wpfbindingreferencexamlparseexception

提问by user2032138

x:Reference can not be resolved after I re-arrange elements in XAML.

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

Here I present a working code. Just move the DataGrid element so it comes after the button element and the bindings for the MenuItem in ContextMenu and MultiBinding in Button.IsEnabled become broken. In Button.IsEnabled only MultiBinding is broken. It can be replaced with commented block and x:Reference works in that single binding.

在这里,我提供了一个工作代码。只需移动 DataGrid 元素,使其位于按钮元素和 ContextMenu 中的 MenuItem 和 Button.IsEnabled 中的 MultiBinding 的绑定被破坏之后。在 Button.IsEnabled 中,只有 MultiBinding 被破坏。它可以用注释块替换,并且 x:Reference 在该单个绑定中工作。

Both throw XamlParseException.

两者都抛出 XamlParseException。

  • MenuItem gives System.Xaml.XamlObjectWriterException and message talks about unresolved reference.
  • MultiBinding gives System.Collections.Generic.KeyNotFoundException as inner exception.
  • MenuItem 给出 System.Xaml.XamlObjectWriterException 和关于未解析引用的消息。
  • MultiBinding 将 System.Collections.Generic.KeyNotFoundException 作为内部异常。

So when is that x:Reference actually resolved and why does only some bindings break when referenced element comes after the element that references it?

那么 x:Reference 什么时候真正解决了,为什么当被引用的元素出现在引用它的元素之后时,为什么只有一些绑定会中断?

Here is my XAML:

这是我的 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>

Here is my Code behind (without usings):

这是我的代码(不使用):

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();
        }
    }
}

回答by Rekshino

I suppose it is because your resources(Window.Resources) will be created first, before referenced instance exists. I would try to solve this through DataContext (ViewModel).

我想这是因为在引用的实例存在之前,您的资源(Window.Resources)将首先被创建。我会尝试通过 DataContext (ViewModel) 来解决这个问题。

<Window.DataContext>
        <yourNameSpace:YourViewModel x:Name="VieModName" />
    </Window.DataContext>
<MenuItem Header="HeadrTxt" Command="{Binding CommandInViewModelCmd}" DataContext="{x:Reference Name=VieModName}" />

回答by shangkeyun

Excerpted from MSDN(http://msdn.microsoft.com/en-us/library/ee795380.aspx).

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

x:Reference is a construct defined in XAML 2009. In WPF, you can use XAML 2009 features, but only for XAML that is not WPF markup-compiled. Markup-compiled XAML and the BAML form of XAML do not currently support the XAML 2009 language keywords and features.

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

回答by Cédric Bignon

x:Referencemust be avoided in WPF. Because this markup extension is a recent addition to the XAML language (2009). And it is not completely supported in WPF. Use ElementNamein your Bindinginstead of x:Reference.

x:Reference在 WPF 中必须避免。因为此标记扩展是最近添加到 XAML 语言 (2009) 中的。而且 WPF 并不完全支持它。使用ElementNameBinding代替x:Reference

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

On MSDN.

MSDN 上