我有一个ListBox,其中包含两个项目的StackPanel,一个Image和一个Textblock。根据用户的要求,我希望能够打开或关闭TextBlock的可见性,从而只显示图像。就像现在一样,每个项目的Image和TextBlock组合是垂直堆叠的,Image是一个完美的正方形(当每个图像下显示TextBlock时,最终会创建一个矩形形状)。当用户希望隐藏TextBlock时,我希望ListBox只显示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
}
据我所知,上述实现确实正确切换了菜单项文本并保存了用户的偏好,以便在返回菜单项时根据用户选择的最后一个选项显示文本,但我不确定如何更改ListBox中每个图像下面的TextBlock的可见性?
编辑**
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 :(得分:3)
使用此方法查找每个ListBoxItem的Textblock
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();
}
使用上面的代码分别显示或隐藏文本块只需更改行
即可 TargetTextBlock.Visibility = Visibility.Visible;
或
TargetTextBlock.Visibility = Visibility.Collapsed;
答案 1 :(得分: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));
}
}
答案 2 :(得分: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>
代码隐藏:
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 :(得分:0)
马修,除了你的问题:
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();
}
}