2013-11-29 4 views
0

У меня есть ListBox, который содержит StackPanel из двух элементов - изображения и текстового блока. По просьбе пользователя я хотел бы включить или отключить видимость TextBlock, таким образом, только показывая изображения. Как и сейчас, комбинация Image и TextBlock для каждого элемента складывается вертикально, и изображение является идеальным квадратом (который в конечном итоге создает прямоугольную форму, когда TextBlock отображается под каждым изображением). Когда пользователь хочет скрыть TextBlock, я хотел бы, чтобы ListBox показывал только элементы StackPanel как единые квадраты для изображений (надеюсь, это имело смысл).Как переключить видимость элемента в StackPanel

Что у меня есть следующие

<ListBox Name="ListBoxEffects" SelectionMode="Single" ItemsSource="{Binding}" Margin="{Binding}" 
        toolkit:TiltEffect.IsTiltEnabled="True" SelectionChanged="ListBox_SelectionChanged" 
         ItemContainerStyle="{StaticResource ListBoxItemStyle1}"> 
        <ListBox.ItemsPanel> 
         <ItemsPanelTemplate> 
          <toolkit:WrapPanel ItemWidth="159" ItemHeight="Auto" /> 
         </ItemsPanelTemplate> 
        </ListBox.ItemsPanel> 
        <ListBox.ItemTemplate> 
         <DataTemplate> 
          <StackPanel Orientation="Vertical" > 
           <Image Source="{Binding Thumbnail}" Width="155" Height="155" /> 
           <TextBlock Text="{Binding Name}" Visibility="{Binding TextBlockVisibility}" TextWrapping="Wrap" FontSize="{StaticResource PhoneFontSizeNormal}" VerticalAlignment="Center" HorizontalAlignment="Center" /> 
          </StackPanel> 
         </DataTemplate> 
        </ListBox.ItemTemplate> 
       </ListBox> 

И в ApplicationBar, созданный в коде за то, где у меня есть пункт меню, который позволит пользователю выбрать его или ее предпочтения на показ или скрытие TextBlock под каждые изображения

private void BuildLocalizedApplicationBar() 
    { 
     ApplicationBar = new ApplicationBar(); 

     ApplicationBarMenuItem showFilterNamesMenuItem = new ApplicationBarMenuItem(); 
     if (Settings.ShowFilterNames.Value) 
      showFilterNamesMenuItem.Text = "Hide names"; 
     else 
      showFilterNamesMenuItem.Text = "Show names"; 
     showFilterNamesMenuItem.Click += showFilterNamesMenuItem_Click; 
     ApplicationBar.MenuItems.Add(showFilterNamesMenuItem); 
    } 

void showFilterNamesMenuItem_Click(object sender, EventArgs e) 
    { 
     if(Settings.ShowFilterNames.Value) 
     { 
      ((ApplicationBarMenuItem)ApplicationBar.MenuItems[0]).Text = "Hide names"; 
      Settings.ShowFilterNames.Value = false; 

      //Toggle the text block visibility to show text here 
     } 
     else 
     { 
      ((ApplicationBarMenuItem)ApplicationBar.MenuItems[0]).Text = "Show names"; 
      Settings.ShowFilterNames.Value = true; 

      //Toggle the text block visibility to hide text here 
     }   
    } 

И проверка выполняются, когда страница перемещаться так, что может быть показало TextBlock под каждое изображение или скрытая соответствующий

protected override void OnNavigatedTo(NavigationEventArgs e) 
    { 
     base.OnNavigatedTo(e); 

     if (Settings.ShowFilterNames.Value)  
      //Show the TextBlocks here 
     else 
      //Hide the TextBlocks here 
    } 

Насколько я могу судить, описанная выше реализация правильно переключает текст пункта меню и сохраняет предпочтения пользователя, так что после возврата текста пункта меню отображается в соответствии с последним выбором, который выбрал пользователь, но я не уверен, как изменить видимость TextBlock под каждым изображением в ListBox?

EDIT **

BooleanToVisibilityConverter.cs

//Error on BooleanToVisibilityConverter stating does not implement interface member 'System.Windows.Data.IValueConverter.Convert(object, System.Type, object, System.Globalization.CultureInfo) 
public class BooleanToVisibilityConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, CultureInfo language)  
    {  
     return (value is bool && (bool)value) ? Visibility.Visible : Visibility.Collapsed;  
    } 
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo language)  
    {  
     return value is Visibility && (Visibility)value == Visibility.Visible;  
    } 
} 

и в XAML

xmlns:common="clr-namespace:TestApp.Common" 

<phone:PhoneApplicationPage.Resources> 
    <common:BooleanToVisibilityConverter x:Key="BoolToVisConv" /> 
</phone:PhoneApplicationPage.Resources> 

<ListBox Name="ListBoxEffects" SelectionMode="Single" ItemsSource="{Binding}" Margin="{Binding}" 
        toolkit:TiltEffect.IsTiltEnabled="True" SelectionChanged="ListBox_SelectionChanged" 
         ItemContainerStyle="{StaticResource ListBoxItemStyle1}"> 
        <ListBox.ItemsPanel> 
         <ItemsPanelTemplate> 
          <toolkit:WrapPanel ItemWidth="159" ItemHeight="Auto" /> 
         </ItemsPanelTemplate> 
        </ListBox.ItemsPanel> 
        <ListBox.ItemTemplate> 
         <DataTemplate> 
          <StackPanel Orientation="Vertical" > 
           <Image Source="{Binding Thumbnail}" Width="155" Height="155" /> 
           <TextBlock Text="{Binding Name}" Visibility="{Binding IsTextBlockVisible, Converter={StaticResource BoolToVisConv}}" TextWrapping="Wrap" FontSize="{StaticResource PhoneFontSizeNormal}" VerticalAlignment="Center" HorizontalAlignment="Center" /> 
          </StackPanel> 
         </DataTemplate> 
        </ListBox.ItemTemplate> 
       </ListBox> 

ответ

0

Visibility свойство является перечисление типа Visibility. Это было бы немного легче, если бы оно было логическим, но это не так.

Необходимо определить статический ресурс для создания экземпляра конвертера BooleanToVisibility, а затем привязать свойство Visibility к булевскому свойству в вашем DataContext. Вот рабочий пример:

<Window x:Class="WpfApplication4.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="MainWindow" Height="350" Width="525"> 
    <Window.Resources> 
     <BooleanToVisibilityConverter x:Key="BoolToVisConv" /> 
    </Window.Resources> 
    <StackPanel> 
     <TextBlock Text="Hide me" Visibility="{Binding IsTextBlockVisible, Converter={StaticResource BoolToVisConv}}" /> 
     <Button Content="Toggle TextBlock" Name="ToggleItButton" Click="ToggleItButton_Click" /> 
</StackPanel> 

public partial class MainWindow : Window, INotifyPropertyChanged { 
    private bool m_IsTextBlockVisible = true; 
    public bool IsTextBlockVisible { 
     get { return m_IsTextBlockVisible; } 
     set { m_IsTextBlockVisible = value; NotifyPropertyChanged("IsTextBlockVisible"); } 
    } 

    public MainWindow() { 
     InitializeComponent(); 
     DataContext = this; 
    } 

    private void ToggleItButton_Click(object sender, RoutedEventArgs e) { 
     IsTextBlockVisible = !IsTextBlockVisible; 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    private void NotifyPropertyChanged(string name) { 
     if (PropertyChanged != null) 
      PropertyChanged(this, new PropertyChangedEventArgs(name)); 
    } 
} 
+0

У меня возникли проблемы с реализацией вашего решения, я программирую для Windows Phone, поэтому он очень похож. Вы создали класс для своего конвертера, который вы ссылаетесь на xaml? Я получаю сообщение об ошибке ''. Я попытался создать класс «BooleanToVisibilityConverter», но у меня также возникли проблемы с этим. Я добавил некоторые изменения выше. – Matthew

+0

См. Http://msdn.microsoft.com/en-us/library/system.windows.controls.booleantovisibilityconverter(v=vs.110).aspx – Steve

0

Вы можете создать два DataTemplate. Один DataTemplate с именем, а другой без имени.

XAML:

<Window ... 
     > 
    <Window.Resources> 
     <DataTemplate x:Key="TemplateWithName"> 
      <StackPanel Orientation="Vertical" > 
       <Image Source="{Binding Thumbnail}" Width="155" Height="155" /> 
       <TextBlock Text="{Binding Name}" TextWrapping="Wrap" VerticalAlignment="Center" HorizontalAlignment="Center" /> 
      </StackPanel> 
     </DataTemplate> 
     <DataTemplate x:Key="TemplateWithoutName"> 
      <StackPanel Orientation="Vertical" > 
       <Image Source="{Binding Thumbnail}" Width="155" Height="155" />    
      </StackPanel> 
     </DataTemplate> 
    </Window.Resources> 
    <Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="30" /> 
      <RowDefinition Height="*" /> 
     </Grid.RowDefinitions> 
     <StackPanel> 
      <ToggleButton x:Name="tbName" Content="Name" Click="tbName_Click" /> 
     </StackPanel> 
     <ListBox Name="ListBoxEffects" SelectionMode="Single" ItemsSource="{Binding}" 
       Grid.Row="1" ItemTemplate="{StaticResource TemplateWithName}"> 
      <ListBox.ItemsPanel> 
       <ItemsPanelTemplate> 
        <WrapPanel ItemWidth="159" ItemHeight="Auto" /> 
       </ItemsPanelTemplate> 
      </ListBox.ItemsPanel>   
     </ListBox> 
    </Grid> 
</Window> 

Code-за:

private void tbName_Click(object sender, RoutedEventArgs e) 
{ 
    if (tbName.IsChecked.Value) 
    { 
     ListBoxEffects.ItemTemplate = this.FindResource("TemplateWithoutName") as DataTemplate; 
    } 
    else 
    { 
     ListBoxEffects.ItemTemplate = this.FindResource("TemplateWithName") as DataTemplate; 
    } 
} 
3

Используйте этот метод, чтобы выяснить ваше TextBlock для каждого ListBoxItem

public static T FindFirstElementInVisualTree<T>(DependencyObject parentElement) where T : DependencyObject 
     { 
      try 
      { 
       int childCount = VisualTreeHelper.GetChildrenCount(parentElement); 
       if (childCount == 0) 
        return null; 

       for (int i = 0; i < childCount; i++) 
       { 
        var child = VisualTreeHelper.GetChild(parentElement, i); 
        if (child != null && child is T) 
        { 
         return (T)child; 
        } 
        else 
        { 
         var result = FindFirstElementInVisualTree<T>(child); 
         if (result != null) 
          return result; 
        } 
       } 
      } 
      catch (Exception ex) 
      { 
       MessageBox.Show(ex.Message); 
      } 
      return null; 
     } 

Этот метод возвращает первый элемент указанный введите из своего DataTemplate. И позволяет вам работать с этим индивидуализированным элементом.

Для этого можно использовать следующий фрагмент кода

for(i=0;i<ListBoxEffects.count;i++) 
    { 
    ListBoxItem item = ListBoxEffects.ItemContainerGenerator.ContainerFromIndex(i) as ListBoxItem; 
    StackPanel TargetStackPanel = common.FindFirstElementInVisualTree<StackPanel>(item); 
    TextBlock TargetTextBlock= TargetStackPanel.Children[1] as TextBlock; 
    TargetTextBlock.Visibility = Visibility.Visible; 
    ListBoxEffects.UpdateLayout(); 
    } 

Используйте приведенный выше код, чтобы показать или скрыть TextBlocks соответственно Просто изменив строку

TargetTextBlock.Visibility = Visibility.Visible; 

или

TargetTextBlock.Visibility = Visibility.Collapsed; 
0

Matthew, дополнение к вашему вопросу:

public class BooleanToVisibilityConverter : IValueConverter 
{ 
    private object GetVisibility(object value) 
    { 
     if (!(value is bool)) 
      return Visibility.Collapsed; 
     bool objValue = (bool)value; 
     if (objValue) 
     { 
      return Visibility.Visible; 
     } 
     return Visibility.Collapsed; 
    } 
    public object Convert(object value, Type targetType, object parameter, string language) 
    { 
     return GetVisibility(value); 
    } 
    public object ConvertBack(object value, Type targetType, object parameter, string language) 
    { 
     throw new NotImplementedException(); 
    } 


} 
Смежные вопросы