Когда разрешается x:Reference в WPF и почему порядок элементов XAML влияет на это?

x: ссылка не может быть разрешена после перестановки элементов в XAML.

Здесь я представляю рабочий код. Просто переместите элемент DataGrid, чтобы он находился после элемента button, и привязки для MenuItem в ContextMenu и MultiBinding в Button.IsEnabled прерываются. В 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>

Вот мой код (без использования):

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 ответа

Я предполагаю, что это потому, что ваши ресурсы (Window.Resources) будут созданы в первую очередь, до того, как существует ссылочный экземпляр. Я хотел бы попытаться решить эту проблему через DataContext (ViewModel).

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

Взято из MSDN ( http://msdn.microsoft.com/en-us/library/ee795380.aspx).

x: Ссылка - это конструкция, определенная в XAML 2009. В WPF вы можете использовать функции XAML 2009, но только для XAML, который не скомпилирован с разметкой WPF. Скомпилированный с разметкой XAML и форма XAML BAML в настоящее время не поддерживают ключевые слова и функции языка XAML 2009.

x:Reference следует избегать в WPF. Потому что это расширение разметки является недавним дополнением к языку XAML (2009). И это не полностью поддерживается в WPF. использование ElementName в вашем Binding вместо x:Reference,

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

На MSDN.

Другие вопросы по тегам