0

I have a flipview which contains photos and descriptions. I want when photo1 be tapped, then descbox1 not visible. And if photo1 be tapped again, then descbox1 will appear.

XAML:

<FlipView x:Name="narrowFlipview"
          ItemsSource="{Binding Group.Items}"
          SelectedItem="{Binding Item, Mode=TwoWay}"
          Foreground="{x:Null}"
          Visibility="Collapsed">
    <FlipView.ItemTemplate>
        <DataTemplate>
            <Grid x:Name="content1"
                  Margin="0,0,0,0">
                <Image x:Name="photo1"
                       Margin="0,0,10,10"
                       Source="{Binding ImagePath}"
                       Tapped="photo_Tapped" />
                <Grid x:Name="detail"
                      VerticalAlignment="Bottom"
                      Height="200">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="auto" />
                        <RowDefinition Height="auto" />
                    </Grid.RowDefinitions>
                    <Button x:Name="hideBtn"
                            Height="50"
                            Width="50"
                            Margin="0,0,5,0"
                            HorizontalAlignment="Right"
                            VerticalAlignment="Bottom"
                            Grid.Row="0"
                            Click="hideBtn_Click">
                        <Button.Background>
                            <ImageBrush Stretch="Uniform"
                                        ImageSource="images/media/ikon-56-app-white-down.png" />
                        </Button.Background>
                    </Button>
                    <Button x:Name="detailBtn"
                            Height="50"
                            Width="50"
                            Margin="0,0,5,0"
                            HorizontalAlignment="Right"
                            VerticalContentAlignment="Bottom"
                            Grid.Row="1"
                            Visibility="Collapsed"
                            Click="detailBtn_Click">
                        <Button.Background>
                            <ImageBrush Stretch="Uniform"
                                        ImageSource="images/media/ikon-56-app-white-up.png" />
                        </Button.Background>
                    </Button>
                    <ScrollViewer x:Name="descBox1"
                                  Grid.Row="1"
                                  Height="150"
                                  Background="#95000000"
                                  VerticalScrollBarVisibility="Auto">
                        <TextBlock x:Name="descriptionText1"
                                   Text="{Binding Description}"
                                   Margin="20,20,20,0"
                                   TextWrapping="Wrap"
                                   TextAlignment="Justify"
                                   VerticalAlignment="Top"
                                   Height="auto"
                                   Foreground="White"
                                   FontSize="21" />
                    </ScrollViewer>
                </Grid>
            </Grid>
        </DataTemplate>
    </FlipView.ItemTemplate>
</FlipView>

I tried using the code below:

private DependencyObject FindChildControl<T>(DependencyObject control, string ctrlName)
        {
            int childNumber = VisualTreeHelper.GetChildrenCount(control);
            for (int i = 0; i < childNumber; i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(control, i);
                FrameworkElement fe = child as FrameworkElement;
                // Not a framework element or is null
                if (fe == null) return null;

                if (child is T && fe.Name == ctrlName)
                {
                    // Found the control so return
                    return child;
                }
                else
                {
                    // Not found it - search children
                    DependencyObject nextLevel = FindChildControl<T>(child, ctrlName);
                    if (nextLevel != null)
                        return nextLevel;
                }
            }
            return null;
        }
    public bool _IsOn;
    public bool IsOn
    {
        get
        {
            return _IsOn;
        }
        set
        {
            _IsOn = value;
        }
    }
    private void photo_Tapped(object sender, TappedRoutedEventArgs e)
    {
ScrollViewer descBox1 = FindChildControl<ScrollViewer>(this, "descBox1") as ScrollViewer;
Button hideBtn = FindChildControl<Button>(this, "hideBtn") as Button;
Button detailBtn = FindChildControl<Button>(this, "detaiBtn") as Button;
        IsOn = !IsOn;
        if (_IsOn)
        {
            descBox1.Visibility = Visibility.Collapsed;
            hideBtn.Visibility = Visibility.Collapsed;
            detailBtn.Visibility = Visibility.Visible;
        }
        else
        {
            descBox1.Visibility = Visibility.Visible;
            hideBtn.Visibility = Visibility.Visible;
            detailBtn.Visibility = Visibility.Collapsed;
        }
    }

But when I tap photo1, descBox1 would not collapse, hiddenBtn would not collapsed, detailBtn would not visible. How to handle it?

Rose
  • 613
  • 4
  • 22
  • This is kind-of related to [Toggling the visibility of a TextBlock in a DataTemplate](https://stackoverflow.com/questions/26800032/windows-phone-8-1-toggling-the-visibility-of-a-textblock-in-a-datatemplate/26801276#26801276). – Decade Moon Oct 25 '16 at 09:35
  • I update the code and experiencing new problems like my post above – Rose Oct 26 '16 at 02:06
  • Did you notice that you only find a single child/object/item. You know you have more than 1 items... – kurakura88 Oct 26 '16 at 03:30
  • @kurakura88 what do you mean of you only find a single child/object/item? Can you correct my code? – Rose Oct 26 '16 at 03:57
  • sorry, I don't have time to fix the whole code. I'll give you hint: change your function to return `List`. Create `List result` and `result.Add(child)` when the control is found. Return the result. In your Tap function, you need to iterate each child and collapse all of them. – kurakura88 Oct 26 '16 at 04:03

1 Answers1

0

According to your requirement, I'd think using Binding here to control these control's visibility would be a simpler solution. For example, we can take advantage of the Tag property.

Ref Remarks in FrameworkElement.Tag property:

The scenario for the Tag property is to provide an general-purpose property on all FrameworkElement classes that supports data binding, animation and styles for itself but where the property's value does not have any implicit meaning to platform subsystems like layout, app model, text, input and so on.

Here we can use this property to store the Visibility and in other controls, bind ther Visibility property to this property like:

<ScrollViewer x:Name="descBox1"
              Grid.Row="1"
              Height="150"
              Background="#95000000"
              VerticalScrollBarVisibility="Auto"
              Visibility="{Binding Tag, ElementName=photo1}">
    <TextBlock x:Name="descriptionText1"
               Height="auto"
               Margin="20,20,20,0"
               VerticalAlignment="Top"
               FontSize="21"
               Foreground="White"
               Text="{Binding Description}"
               TextAlignment="Justify"
               TextWrapping="Wrap" />
</ScrollViewer>

Then in photo_Tapped method, we can change Tag's value to control the visibility of "descBox1".

private void photo_Tapped(object sender, TappedRoutedEventArgs e)
{
    var tag = (sender as Image)?.Tag?.ToString();
    //if we didn't set Tag in Image, its value should be null and descBox1 will be Visible 
    if (string.IsNullOrEmpty(tag) || tag.Equals("Visible"))
    {
        (sender as Image).Tag = Visibility.Collapsed;
    }
    else
    {
        (sender as Image).Tag = Visibility.Visible;
    }
}

"hiddenBtn" is similar, we only need to set the Mode of the Binding to TwoMay, so that when we change its visibility, "descBox1" and "detailBtn" will also change their visibility automatically.

<Button x:Name="hideBtn"
        Grid.Row="0"
        Width="50"
        Height="50"
        Margin="0,0,5,0"
        HorizontalAlignment="Right"
        VerticalAlignment="Bottom"
        Click="hideBtn_Click"
        Visibility="{Binding Tag, ElementName=photo1, Mode=TwoWay}">
    <Button.Background>
        <ImageBrush ImageSource="images/media/ikon-56-app-white-down.png" Stretch="Uniform" />
    </Button.Background>
</Button>

private void hideBtn_Click(object sender, RoutedEventArgs e)
{
    ChangeButtonVisibility(sender);
}

private void ChangeButtonVisibility(object sender)
{
    var visibility = (sender as Button)?.Visibility;
    if (visibility.Equals(Visibility.Visible))
    {
        (sender as Button).Visibility = Visibility.Collapsed;
    }
    else
    {
        (sender as Button).Visibility = Visibility.Visible;
    }
}

"detailBtn" is the same as "hiddenBtn", but its visibility is opposite to "hiddenBtn". So we will need a InvertedVisibilityConverter like following:

public class InvertedVisibilityConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        return InvertedVisibility(value);
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        return InvertedVisibility(value);
    }

    private object InvertedVisibility(object value)
    {
        var visibility = value?.ToString();
        if (string.IsNullOrEmpty(visibility) || visibility.Equals("Visible"))
        {
            return Visibility.Collapsed;
        }
        else
        {
            return Visibility.Visible;
        }
    }
}

And in "detailBtn", setting Binding like following:

<Button x:Name="detailBtn"
        Grid.Row="1"
        Width="50"
        Height="50"
        Margin="0,0,5,0"
        HorizontalAlignment="Right"
        VerticalContentAlignment="Bottom"
        Click="detailBtn_Click"
        Visibility="{Binding Tag, ElementName=photo1, Mode=TwoWay, Converter={StaticResource InvertedVisibilityConverter}}">
    <Button.Background>
        <ImageBrush ImageSource="images/media/ikon-56-app-white-up.png" Stretch="Uniform" />
    </Button.Background>
</Button>

private void detailBtn_Click(object sender, RoutedEventArgs e)
{
    ChangeButtonVisibility(sender);
}

Update: To make the visibilities in all FlipViewItems have the same behavior, we need a dependence property that can store the visibility "globally". So we can use FlipView's Tag property instead of Image's Tag property and in Image set the Binding like following:

<Image x:Name="photo1"
       Margin="0,0,10,10"
       Source="{Binding ImagePath}"
       Tag="{Binding Tag, ElementName=narrowFlipview, Mode=TwoWay}"
       Tapped="photo_Tapped" />

After this all Image's Tag will have the same value. And as this is a two-way binding, when we change one Image's Tag value, it will automatically change FlipView.Tag's value and then propagate to all other Images.

In other controls like "descBox1", "hiddenBtn" and "detailBtn", we can also change their Binding by change ElementName from photo1 to narrowFlipview. Using "detailBtn" for example:

<Button x:Name="detailBtn"
        Grid.Row="1"
        Width="50"
        Height="50"
        Margin="0,0,5,0"
        HorizontalAlignment="Right"
        VerticalContentAlignment="Bottom"
        Click="detailBtn_Click"
        Visibility="{Binding Tag, ElementName=narrowFlipview, Mode=TwoWay, Converter={StaticResource InvertedVisibilityConverter}}">
    <Button.Background>
        <ImageBrush ImageSource="images/media/ikon-56-app-white-up.png" Stretch="Uniform" />
    </Button.Background>
</Button>

And there is no need to change the code-behind, after editing the Bindings in XAML, it should be able to achieve what you want.

Jay Zuo
  • 15,653
  • 2
  • 25
  • 49
  • when i try to add Visibility="{Binding Tag, ElementName=photo1, Mode=TwoWay, Converter={StaticResource InvertedVisibilityConverter}}" in detailBtn, display error message: The resource "InvertedVisibilityConverter" could not be resolved. Note: I've made a InvertedVisibilityConverter class. – Rose Oct 28 '16 at 02:02
  • I would like if photo1 on tap, then descbox1 not visible, hideBtn not visible, detailBtn visible. And if photo1 on the tap again, then descbox1 visible, hideBtn visible, detailBtn not visible. And so on. Note: photo1 remain visible, even in tap repeatedly. – Rose Oct 28 '16 at 02:12
  • @Rose I didn't change photo1's visibility, you do not need to change photo1's XAML code. And for `InvertedVisibilityConverter`, please make sure you have added it in `Page.Resources` like `` then clean and rebuild your project. There should be no error. – Jay Zuo Oct 28 '16 at 02:15
  • zhou: i have to try your code, but when i tapped the photo, the descBox1 did not collapsed. How to handle it? – Rose Oct 28 '16 at 05:07
  • @Rose Could you share a [mcve] that can reproduce your issue? The code works well in my side. – Jay Zuo Oct 28 '16 at 05:31
  • here the project: https://drive.google.com/file/d/0B4oRSWSS0hKDWWhNdHJlYllVR3M/view?usp=sharing – Rose Oct 28 '16 at 07:28
  • @Rose You are binding the wrong element. In my solution, I'm using `photo1`'s `Tag` property to store and control other controls' visibility. "descBox1", "hiddenBtn" and "detailBtn" are binding their `Visibility` to `photo1`'s `Tag` property. Once you change your Binding as in my code, your project should be able to work. – Jay Zuo Oct 28 '16 at 07:51
  • There is a new problem, see photo1 and descBox1 on flipview not the same. There are some defaults photo1 visible, descbox1 visible, hideBtn1 seen, detailBtn1 not visible. There is also a visible photo1, descbox1 invisible, hideBtn1 invisible, visible detailBtn1. I want to default photo1 visible, descbox1 visible, hideBtn1 seen, detailBtn1 not visible. I would also like if photo1 on tap, then descbox1 seen, hideBtn1 seen, detailBtn1 not visible at all photo1 on flipview. – Rose Oct 28 '16 at 08:37
  • @Rose Seems you want all `FlipViewItem`s have the same behavior after tap one photo1, if so please see my updated answer. The solution is similar, what we need is using FlipView's Tag property instead of Image's Tag property to store the visibility "globally". – Jay Zuo Oct 28 '16 at 10:37
  • I've tried the code above, but flipview becomes not appear. I have 2 flipview and use visualstate well. When the size of the screen resolution of at least 500, it would appear narrowflipview. If the screen size is greater than 500, then it will use wideflipview. Are things that cause flipview tersebit not appear? – Rose Oct 31 '16 at 01:47
  • @Rose In my solution, I didn't change FlipView's visibility. It should not be disappeared. I tested with the project you've shared and it works well. For your new issue, I'd suggest you ask a new question with details and the shortest code necessary to reproduce it in the question itself. – Jay Zuo Oct 31 '16 at 02:21