2016-06-26 8 views
0

Я создаю шаблонный элемент управления для приложения UWP, и я попал в ловушку при попытке привязки во вложенном DataTemplate. Вот мой управления XAML в Themes/Generic.xaml:XAML TemplateBinding в DataTemplate

<Style TargetType="local:EnhancedListView"> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="local:EnhancedListView"> 
       <Grid HorizontalAlignment="Stretch"> 
        <Grid.Resources> 
         <DataTemplate x:Key="ListViewTemplate"> 
          <Grid> 
           <Grid.ColumnDefinitions> 
            <ColumnDefinition /> 
            <ColumnDefinition /> 
           </Grid.ColumnDefinitions> 
           <CheckBox Visibility="{Binding RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource BooleanToVisibilityConverter}, Path=IsCheckModeEnabled}" Grid.Column="0" /> 
           <TextBlock Text="{Binding}" Grid.Column="1" /> 
          </Grid> 
         </DataTemplate> 
        </Grid.Resources> 
        <Grid.RowDefinitions> 
         <RowDefinition /> 
         <RowDefinition /> 
        </Grid.RowDefinitions> 
        <CheckBox Visibility="{Binding RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource BooleanToVisibilityConverter}, Path=IsCheckModeEnabled}" Grid.Row="0">Hello</CheckBox> 
        <ListView Grid.Row="1" ItemsSource="{TemplateBinding ItemsSource}" ItemTemplate="{StaticResource ListViewTemplate}" /> 
       </Grid> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 

Вот мой фактический контроль/преобразователь:

public class EnhancedListView : Control 
{ 
    public EnhancedListView() 
    { 
     DefaultStyleKey = typeof(EnhancedListView); 
    } 

    public object ItemsSource 
    { 
     get { return GetValue(ItemsSourceProperty); } 
     set { SetValue(ItemsSourceProperty, value); } 
    } 

    public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(object), typeof(EnhancedListView), new PropertyMetadata(null)); 

    public bool IsCheckModeEnabled 
    { 
     get { return (bool)GetValue(IsCheckModeEnabledProperty); } 
     set { SetValue(IsCheckModeEnabledProperty, value); } 
    } 

    public static readonly DependencyProperty IsCheckModeEnabledProperty = DependencyProperty.Register("IsCheckModeEnabled", typeof(bool), typeof(EnhancedListView), new PropertyMetadata(null)); 
} 

public class BooleanToVisibilityConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, string language) 
    { 
     return (bool)value ? Visibility.Visible : Visibility.Collapsed; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, string language) 
    { 
     throw new NotSupportedException(); 
    } 
} 

Вот MainPage.xaml:

<local:EnhancedListView IsCheckModeEnabled="False" x:Name="ctlListView"> 
</local:EnhancedListView> 

И, наконец, мой MainPage .xaml.cs:

public MainPage() 
    { 
     this.InitializeComponent(); 

     ctlListView.ItemsSource = new List<string> { "Item 1", "Item 2" }; 
    } 

Как и следовало ожидать, при загрузке страницы первый флажок скрывается, поскольку IsCheckModeEnabled является ложным, но все флажки, вложенные в DataTemplate, все еще видны.

Я пробовал обертывать это в StaticResource, как предлагалось here, но он не работает с некоторыми сложными типами, такими как вложение другого DataTemplate в мой DataTemplate.

Я уверен, привязка не совсем прямо на собственность Видимость здесь:

<CheckBox Visibility="{Binding RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource BooleanToVisibilityConverter}, Path=IsCheckModeEnabled}" Grid.Column="0" />

Спасибо за вашу помощь!

+0

Без хорошей [mcve], которая надежно воспроизводит проблему, невозможно точно знать, в чем проблема, не говоря уже о лучшем исправлении. Но похоже, что вы ошибочно полагаете, что шаблонный родительский элемент элемента в «ListView» совпадает с шаблоном родителя шаблона, содержащего этот «ListView». Если этого недостаточно, чтобы указать вам в правильном направлении, пожалуйста, улучшите свой вопрос. –

+1

И где смысл в написании 'DataContext = {{Binding}" '? – Clemens

+0

@PeterDuniho - Я добавил дополнительные сведения, чтобы улучшить вопрос. Я также не «ошибочно полагаю», что родитель шаблона элемента «ListView» совпадает с родительским контейнером, я просто не знаю, как его представлять и привязывать к нему. – Matt

ответ

0

Только предположение, но как об этом:

<CheckBox Visibility="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:EnhancedListView}, Converter={StaticResource BooleanToVisibilityConverter}, Path=IsCheckModeEnabled}" DataContext="{Binding}" Grid.Column="0" /> 

Кстати: человек это запутанное ...

+0

Спасибо, но, к сожалению, это не работает, поскольку AncestorType недействителен: 'Неизвестный член 'AncestorType' on element 'RelativeSource'' – Matt

+0

oh yeah, right, uwp ... –

+0

еще одно предложение, вы пробовали играть с ListViews SelectionMode = multiple? Я мог бы представить стиль, который позволяет использовать флажки, когда этот режим применяется ... –

0

Я полагаю, что я нашел «чистое» решение, которое работает. Я создал новый EnhancedListViewItem класс, который может имитировать свойства на EnhancedListView. Тогда я задаю и стиль, который EnhancedListViewItem независимо от родительского EnhancedListView. Вот мой обновленный Generic.xaml:

<Style TargetType="local:EnhancedListView"> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="local:EnhancedListView"> 
       <Grid HorizontalAlignment="Stretch"> 
        <Grid.RowDefinitions> 
         <RowDefinition /> 
         <RowDefinition /> 
        </Grid.RowDefinitions> 
        <CheckBox Visibility="{Binding RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource BooleanToVisibilityConverter}, Path=IsCheckModeEnabled}" Grid.Column="0" /> 
        <ListView Grid.Row="1" ItemsSource="{TemplateBinding ItemsSource}" /> 
       </Grid> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 

<Style TargetType="local:EnhancedListViewDataItem"> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="local:EnhancedListViewDataItem"> 
       <Grid HorizontalAlignment="Stretch"> 
        <Grid.ColumnDefinitions> 
         <ColumnDefinition /> 
         <ColumnDefinition /> 
        </Grid.ColumnDefinitions> 
        <CheckBox Visibility="{Binding RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource BooleanToVisibilityConverter}, Path=IsCheckModeEnabled}" Grid.Column="0" /> 
        <TextBlock Text="{Binding}" Grid.Column="1" /> 
       </Grid> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 

А вот мой обновленный код позади элементов управления:

public class EnhancedListView : Control, INotifyPropertyChanged 
{ 
    public EnhancedListView() 
    { 
     DefaultStyleKey = typeof(EnhancedListView); 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    public object ItemsSource 
    { 
     get { return GetValue(ItemsSourceProperty); } 
     set 
     { 
      var boundItems = new List<EnhancedListViewDataItem>(); 

      foreach (var obj in (List<string>)value) 
      { 
       boundItems.Add(new EnhancedListViewDataItem(this) 
       { 
        DataContext = obj 
       }); 
      } 

      SetValue(ItemsSourceProperty, boundItems); 
     } 
    } 

    public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(object), typeof(EnhancedListView), new PropertyMetadata(null)); 

    public bool IsCheckModeEnabled 
    { 
     get { return (bool)GetValue(IsCheckModeEnabledProperty); } 
     set 
     { 
      SetValue(IsCheckModeEnabledProperty, value); 
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsCheckModeEnabled")); 
     } 
    } 

    public static readonly DependencyProperty IsCheckModeEnabledProperty = DependencyProperty.Register("IsCheckModeEnabled", typeof(bool), typeof(EnhancedListView), new PropertyMetadata(null)); 
} 

public class EnhancedListViewDataItem : ListViewItem 
{ 
    public EnhancedListViewDataItem(EnhancedListView listView) 
    { 
     _listView = listView; 
     _listView.PropertyChanged += _listView_PropertyChanged; 
     DefaultStyleKey = typeof(EnhancedListViewDataItem); 
    } 

    private readonly EnhancedListView _listView; 

    private void _listView_PropertyChanged(object sender, PropertyChangedEventArgs e) 
    { 
     IsCheckModeEnabled = _listView.IsCheckModeEnabled; 
    } 

    public bool IsCheckModeEnabled 
    { 
     get { return (bool)GetValue(IsCheckModeEnabledProperty); } 
     set { SetValue(IsCheckModeEnabledProperty, value); } 
    } 

    public static readonly DependencyProperty IsCheckModeEnabledProperty = DependencyProperty.Register("IsCheckModeEnabled", typeof(bool), typeof(EnhancedListViewDataItem), new PropertyMetadata(null)); 
} 
Смежные вопросы