开发者

Displaying Content only when ListViewItem is Selected

I have a ListBox when one of the ListBoxItems are selected I want to change the visibility of the button "View" and display it. Meaning that the default state is Hidden.

Is this possible and if so, do I solve this with a trigger in XAML or in code behind?

XAML Piece

<ListBox Background="Transparent" 
      ItemContainerStyle="{StaticResource listBoxTemplate}" BorderThickness="0">
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Vertical" VerticalAlignment="Center" />
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Grid Background="Beige" Margin="10 10 10 10" 
                    HorizontalAlignment="Center" Width="500" Height="100"
                    VerticalAlignment="Stretch">
                <Grid.RowDefinitions>
                    <RowDefinition Name="TopRow" Height="50" />
          开发者_如何学C          <RowDefinition Name="BottomRow" Height="*" />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Name="LeftSideMenu" Width="*"/>
                    <ColumnDefinition Name="Middle" Width="*"/>
                </Grid.ColumnDefinitions>
                <Label Grid.Column="0" Grid.Row="0" Content="{Binding name}" />

                <Button Grid.Column="1" VerticalAlignment="Center" 
                    Grid.RowSpan="2" Name="view" Click="viewClicked_Click"
                    Grid.Row="0">View</Button>

                <Label Grid.Column="0" Grid.Row="1" 
                    Content="{Binding description}" />
            </Grid>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>


[Old useless code]


EDIT: Well I didn't read the question good enough but this should do the trick: Replace the button in your DataTemplate with this:

<Button Grid.Row="0" Grid.Column="1" Grid.RowSpan="2" VerticalAlignment="Center"
        Name="view" Click="viewClicked_Click"
        Content="View">
 <Button.Style>
  <Style TargetType="{x:Type Button}">
   <Setter Property="Visibility" Value="Collapsed"/>
   <Style.Triggers>
    <DataTrigger Binding="{Binding 
                           RelativeSource={RelativeSource Mode=FindAncestor,
                           AncestorType={x:Type ListBoxItem}},Path=IsSelected}" 
                 Value="True">
     <Setter Property="Visibility" Value="Visible"/>
    </DataTrigger>
   </Style.Triggers>
  </Style>
 </Button.Style>
</Button>

What happends here is that the style sets the Visibility property to Collapsed and uses a trigger to change that. I've used a DataTrigger so you can use the {Binding ...}. With the {Binding RelativeSource={..}} you can look for an Ancestor, here we are looking for an Ancestor of type ListBoxItem.

What this does is look 'up' in the WPF tree to see if this button has a Parent object which is of type ListBoxItem if it's found it will check the IsSelected (Path=IsSelected) property if it's True and will then update the Visibility Property of the button.

I hope this explanation makes sense! :-)


EDIT2: Just for fun, the code behind way:

private Button _previousButton;
private void listBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
 if (_previousButton != null)
  _previousButton.Visibility = Visibility.Collapsed;

 // Make sure an item is selected
 if (listBox.SelectedItems.Count == 0)
  return;

 // Get the first SelectedItem (use a List<object> when 
 // the SelectionMode is set to Multiple)
 object selectedItem = listBox.SelectedItems[0];
 // Get the ListBoxItem from the ContainerGenerator
 ListBoxItem listBoxItem = listBox.ItemContainerGenerator.ContainerFromItem(selectedItem) as ListBoxItem;
 if (listBoxItem == null)
  return;

 // Find a button in the WPF Tree
 Button button = FindDescendant<Button>(listBoxItem);
 if (button == null)
  return;

 button.Visibility = Visibility.Visible;
 _previousButton = button;
}

/// <summary>
/// Finds the descendant of a dependency object.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj">The obj.</param>
/// <returns></returns>
public static T FindDescendant<T>(DependencyObject obj) where T : DependencyObject
{
 // Check if this object is the specified type
 if (obj is T)
  return obj as T;

 // Check for children
 int childrenCount = VisualTreeHelper.GetChildrenCount(obj);
 if (childrenCount < 1)
  return null;

 // First check all the children
 for (int i = 0; i < childrenCount; i++)
 {
  DependencyObject child = VisualTreeHelper.GetChild(obj, i);
  if (child is T)
   return child as T;
 }

 // Then check the childrens children
 for (int i = 0; i < childrenCount; i++)
 {
  DependencyObject child = FindDescendant<T>(VisualTreeHelper.GetChild(obj, i));
  if (child != null && child is T)
   return child as T;
 }

 return null;
}

I suggest you use the XAML Trigger "way" because it's much cleaner...


Use a converter on the selected item on the list to determine the visibility.

<Button Visibility="{Binding ElementName=lb, Path=SelectedItem, Converter={StaticResource TestConverter}}" />

Here is the value converter

public class TestConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null)
            return Visibility.Collapsed;
        else
            return Visibility.Visible;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new Exception("The method or operation is not implemented.");
    }
}


If you're using the MVVM pattern, you should bind your button to an ICommand such as the DelegateCommand from the MVVM Toolkit. That way the button will use the command's CanExecute() state to decide for itself whether it should be enabled or not.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜