2013-02-01 14 views
10

x: Tham chiếu không thể giải quyết được sau khi tôi sắp xếp lại các phần tử trong XAML.Khi nào x: Tham chiếu trong WPF được giải quyết và tại sao thứ tự phần tử XAML ảnh hưởng đến nó?

Ở đây tôi trình bày mã hoạt động. Chỉ cần di chuyển phần tử DataGrid để nó xuất hiện sau phần tử nút và các ràng buộc cho MenuItem trong ContextMenu và MultiBinding trong Button.IsEnabled bị hỏng. Trong Button.IsEnabled chỉ MultiBinding bị hỏng. Nó có thể được thay thế bằng khối nhận xét và x: Tham chiếu hoạt động trong liên kết đơn.

Cả hai ném XamlParseException.

  • MenuItem cung cấp cho System.Xaml.XamlObjectWriterException và thông báo về nội dung chưa được giải quyết.
  • MultiBinding cung cấp cho System.Collections.Generic.KeyNotFoundException làm ngoại lệ bên trong.

Vì vậy, khi nào x: Tham chiếu thực sự được giải quyết và tại sao chỉ một số ràng buộc phá vỡ khi phần tử được tham chiếu đến sau phần tử tham chiếu?

Đây là XAML của tôi:

<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> 

Đây là Mã của tôi đằng sau (không 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(); 
     } 
    } 
} 

Trả lời

-2

x:Reference phải tránh trong WPF. Bởi vì phần mở rộng đánh dấu này là một bổ sung gần đây cho ngôn ngữ XAML (2009). Và nó không hoàn toàn được hỗ trợ trong WPF. Sử dụng ElementName trong số Binding thay vì x:Reference của bạn.

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

Trên MSDN.

+1

Vấn đề là đôi khi ElementName không tìm thấy phần tử. Và đó là lý do ban đầu tôi sử dụng x: Tham khảo ở nơi đầu tiên. Như tôi đã hiểu x: Tham chiếu là một cách giải quyết cho ElementName khi nó không hoạt động. Điều gì về trường hợp mà không phải của họ làm việc? Ví dụ trong trường hợp này bằng cách sử dụng ElementName làm việc cho MultiBinding trong Button.IsEnabled nhưng không hoạt động để kích hoạt mục menu ngữ cảnh. – user2032138

+0

@ user2032138 Nó được giải thích trong bài viết MSDN, "nhưng chỉ cho XAML không phải là WPF đánh dấu biên soạn." –

+1

Vì vậy, trong tình huống này khi XAML mô tả giao diện người dùng chính của việc sử dụng ứng dụng của x: Tham chiếu không được hỗ trợ? – user2032138

0

Trích từ MSDN (http://msdn.microsoft.com/en-us/library/ee795380.aspx).

x: Tham chiếu là cấu trúc được xác định trong XAML 2009. Trong WPF, bạn có thể sử dụng các tính năng XAML 2009, nhưng chỉ cho XAML không phải là WPF được đánh dấu biên dịch. XAML được đánh dấu đã biên dịch và dạng XAML BAML hiện không hỗ trợ các từ khóa và tính năng XAML 2009 ngôn ngữ.

1

Tôi cho rằng đó là vì tài nguyên của bạn (Window.Resources) sẽ được tạo trước tiên, trước khi thể hiện tham chiếu tồn tại. Tôi sẽ cố gắng giải quyết điều này thông qua DataContext (ViewModel).

<Window.DataContext> 
     <yourNameSpace:YourViewModel x:Name="VieModName" /> 
    </Window.DataContext> 
<MenuItem Header="HeadrTxt" Command="{Binding CommandInViewModelCmd}" DataContext="{x:Reference Name=VieModName}" /> 
Các vấn đề liên quan