tags:

views:

118

answers:

3

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" />
                    <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>
+1  A: 

[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.Column="1" VerticalAlignment="Center"
  Grid.RowSpan="2" Name="view" Click="viewClicked_Click"
  Grid.Row="0" 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...

Zenuka
This displays ALL buttons, for each item. The button is in each element. So your answer is wrong :/
Filip Ekberg
Ooh sorry, see what you mean...
Zenuka
Yes, I've tried it. But you are missing the point. The Buttons are REPEATED inside the ListBox. Each ListBoxItem consists of a StackPanel. See my example please. Your example works if you want to display ONE button NOT in the List.
Filip Ekberg
Good, hehe! Sorry if my code was a little missleading.
Filip Ekberg
The edit should do the trick
Zenuka
Awesome! This did the trick. Care to elaborate on what you really did there? Maybe point out a good explenation of these types of bindings?
Filip Ekberg
I hope I made sense in my explanation!
Zenuka
Neat! thanks a lot!
Filip Ekberg
A: 

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.");
    }
}
mdm20
You'll need to check if the SelectedItem is the same as the ListBoxItem the button is in...
Zenuka
Yah, I misunderstood the question.
mdm20
A: 

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.

Groky