locked
[UWP][C++] How to close Flyout from inner flyout button on dynamically generated Flyout RRS feed

  • Question

  • Given a gridview such as

    <GridView 
        ScrollViewer.VerticalScrollBarVisibility="Visible"
        IsItemClickEnabled="True"
        ItemsSource="{x:Bind FavoriteTagViewModel.TagBinders}" 
        HorizontalAlignment="Stretch"
        HorizontalContentAlignment="Stretch" 
        >
        <GridView.ItemContainerStyle>
            <Style TargetType="GridViewItem">
                <Setter  Property="HorizontalContentAlignment" Value="Stretch" />
                <Setter Property="VerticalContentAlignment"  Value="Stretch" />
            </Style>
        </GridView.ItemContainerStyle>
        <GridView.Resources>
            
        </GridView.Resources>
        <GridView.ItemTemplate     >
            <DataTemplate  x:DataType="local:TagBinder">
                <Button  x:Name="ourbutton" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="{x:Bind Name, Mode=OneWay}">
                    <Button.Flyout >
                        <Flyout  >
                            <StackPanel AccessKey="{x:Bind Id,Mode=OneWay}">
                                <TextBlock  Text="Remove Tag From Favorite?" Margin="0,0,0,12" />
                                <Button Click="ConfirmFavoriteTag" AccessKey="{x:Bind Id,Mode=OneWay}" Content="Yes, remove tag" />
                            </StackPanel>
                        </Flyout>
                    </Button.Flyout>
                </Button>
            </DataTemplate>
        </GridView.ItemTemplate>

    How can I close they flyout when calling ConfirmFavoriteTag?

    void FavoriteItemPage::ConfirmFavoriteTag(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args) {
    	// Close flyout here!	
    }

    Sunday, November 17, 2019 2:21 PM

Answers

  • Hi,

    There are some grammatical errors, like e.NewValue().as<bool>();. We can't use as method  to convert IInspectable to bool, we need to use winrt::unbox_value, it's my fault, I misled you. And here is a simple sample I created that you can check it, I only create one button to operate it, when you want to put the button in listView, you need to change the viewmodel depending on the actual situation. Hope this could help you.

    By the way, We invite you to post new questions in the "Developing Universal Windows apps" forum’s new home on Microsoft Q&A (Preview)!

    Best Regards,

    Fay


    "Developing Universal Windows apps" forum will be migrating to a new home on Microsoft Q&A (Preview)!
    We invite you to post new questions in the "Developing Universal Windows apps" forum’s new home on Microsoft Q&A (Preview)!
    For more information, please refer to the sticky post.



    Wednesday, November 20, 2019 8:58 AM

All replies

  • Hi,

    You can define a new Attached Property to control the display and hide of the flyout. For example, add a property named IsOpen like below and you also need to define a parent property to show the flyout on it. And  for more details about how to add an attached property, you can refer to this document which is about how to add a dependency property. More detailed steps, you can check this document.

     

    FlyoutHelpers.idl:

    static Windows.UI.Xaml.DependencyProperty IsOpenProperty{ get; };
    Boolean IsOpen;
    
    static Windows.UI.Xaml.DependencyProperty ParentProperty{ get; };
    Windows.UI.Xaml.Controls.Button Parent;

    FlyoutHelpers.cpp:

    Windows::UI::Xaml::DependencyProperty MainPage::m_isopenProperty = Windows::UI::Xaml::DependencyProperty::RegisterAttached(

    L"IsOpen",

    winrt::xaml_typename<bool>(),

    winrt::xaml_typename<MyApp::MainPage>(),

    Windows::UI::Xaml::PropertyMetadata{ false, Windows::UI::Xaml::PropertyChangedCallback{ &FlyoutHelpers::OnLabelChanged } } );

    Windows::UI::Xaml::DependencyProperty MainPage::m_parentProperty = Windows::UI::Xaml::DependencyProperty::RegisterAttached(

    L"Parent",

    winrt::xaml_typename<Button>(),

    winrt::xaml_typename<MyApp::MainPage>(),

    Windows::UI::Xaml::PropertyMetadata{ false, nullptr } );

    void OnIsOpenPropertyChanged(DependencyObject d,
    Windows::UI::Xaml::DependencyPropertyChangedEventArgs e)
    {
    Windows::UI::Xaml::Controls::Flyout flyout = d.as<Windows::UI::Xaml::Controls::Flyout>();

    auto parent = d.GetValue(m_parentProperty).as<Windows::UI::Xaml::Controls::Button>();


    if (flyout != nullptr && parent != nullptr)
    {
    auto newValue = e.NewValue().as<bool>();

    if (newValue)
    flyout.ShowAt(parent);
    else
    flyout.Hide();
    }
    }


    MainPage.xaml:

    <Button  x:Name="ourbutton" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="FlyoutButton1">                       

    <Button.Flyout>                           

    <Flyout local:FlyoutHelpers.IsOpen="{x:Bind MyVM.IsFlyoutOpen,Mode=OneWay}" local:FlyoutHelpers.Parent="{Binding ElementName=ourbutton}"> 

            <StackPanel>   ......

    </StackPanel>                           

    </Flyout>                       

    </Button.Flyout>                   

    </Button>

    MainPage.cpp:

    void MainPage::ConfirmFavoriteTag(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args) {

    MyVM.IsFlyoutOpen = false;

    }

    Besides, we invite you to post new questions in the "Developing Universal Windows apps" forum’s new home on Microsoft Q&A (Preview)!

    Best Regards,

    Fay



    "Developing Universal Windows apps" forum will be migrating to a new home on Microsoft Q&A (Preview)!
    We invite you to post new questions in the "Developing Universal Windows apps" forum’s new home on Microsoft Q&A (Preview)!
    For more information, please refer to the sticky post.


    Monday, November 18, 2019 3:34 AM
  • Thank you. I haven't gone through the Custom templated controls tutorial yet. This is a good opportunity to learn it.
    Monday, November 18, 2019 3:43 AM
  • I have tried to follow along with what you are saying. However it is proving to be really complicated. I feel like this is a very common need so it would be good to have a complete answer here.

    Here is my c++ for FlyoutHelpers.cpp

    #include "pch.h"
    #include "FlyoutHelpers.h"
    #include "FlyoutHelpers.g.cpp"
    
    // Note: Remove this static_assert after copying these generated source files to your project.
    // This assertion exists to avoid compiling these generated source files directly.
    
    
    namespace winrt::myapp::implementation
    {
    
       Windows::UI::Xaml::DependencyProperty FlyoutHelpers::m_isopenProperty = Windows::UI::Xaml::DependencyProperty::RegisterAttached(
    
    		L"IsOpen",			
    
                    winrt::xaml_typename<bool>(),			
    
                    winrt::xaml_typename<myapp::FlyoutHelpers>(),
    
    	   Windows::UI::Xaml::PropertyMetadata{ false, nullptr });
    
    	Windows::UI::Xaml::DependencyProperty FlyoutHelpers::m_parentProperty = Windows::UI::Xaml::DependencyProperty::RegisterAttached(
    
    		L"Parent",			
    
                    winrt::xaml_typename<Windows::UI::Xaml::Controls::Button>(),
    
                    winrt::xaml_typename<myapp::FlyoutHelpers>(),
    
                    Windows::UI::Xaml::PropertyMetadata{ false, nullptr }	);
    
    void FlyoutHelpers::OnIsOpenPropertyChanged(Windows::UI::Xaml::DependencyObject d,
    		Windows::UI::Xaml::DependencyPropertyChangedEventArgs e)
    	{
    		Windows::UI::Xaml::Controls::Flyout flyout = d.as<Windows::UI::Xaml::Controls::Flyout>();
    
    		auto parent = d.GetValue(ParentProperty()).as<Windows::UI::Xaml::Controls::Button>();
    		
    
    		if (flyout != nullptr && parent != nullptr)
    		{
    			auto newValue = e.NewValue().as<bool>();
    
    			if (newValue)
    				flyout.ShowAt(parent);
    			else
    				flyout.Hide();
    		}
    	} 
    
    
    
        Windows::UI::Xaml::DependencyProperty FlyoutHelpers::IsOpenProperty()
        {
    
    		//return winrt::unbox_value<winrt:: >(GetValue(m_isopenProperty));
    		return   m_isopenProperty;
        }
        Windows::UI::Xaml::DependencyProperty FlyoutHelpers::ParentProperty()
        {
    		return m_parentProperty;
        }
        bool FlyoutHelpers::IsOpen()
        {
    		return winrt::unbox_value<bool>(GetValue(this->m_isopenProperty));
        }
        void FlyoutHelpers::IsOpen(bool value)
        {
    		SetValue(this->m_isopenProperty, winrt::box_value(value));
           
        }
        Windows::UI::Xaml::Controls::Button FlyoutHelpers::Parent()
        {
    		return winrt::unbox_value<Windows::UI::Xaml::Controls::Button>(GetValue(this->m_parentProperty));
        }
        void FlyoutHelpers::Parent(Windows::UI::Xaml::Controls::Button const& value)
        {
    		SetValue(this->m_parentProperty, winrt::box_value(value));
        }
    }
    
    Here is my .h file.

    #pragma once
    #include "FlyoutHelpers.g.h"
    
    // Note: Remove this static_assert after copying these generated source files to your project.
    // This assertion exists to avoid compiling these generated source files directly.
    
    
    namespace winrt::myapp::implementation
    {
        struct FlyoutHelpers : FlyoutHelpersT<FlyoutHelpers>
        {
            FlyoutHelpers() = default;
    
    		static Windows::UI::Xaml::DependencyProperty IsOpenProperty();
            static Windows::UI::Xaml::DependencyProperty ParentProperty();
            bool IsOpen();
            void IsOpen(bool value);
            Windows::UI::Xaml::Controls::Button Parent();
            void Parent(Windows::UI::Xaml::Controls::Button const& value);
    		void OnIsOpenPropertyChanged(Windows::UI::Xaml::DependencyObject d,
    			Windows::UI::Xaml::DependencyPropertyChangedEventArgs e);
    		private:
    			static Windows::UI::Xaml::DependencyProperty m_isopenProperty;
    			static Windows::UI::Xaml::DependencyProperty m_parentProperty;
    
        };
    }
    namespace winrt::myapp::factory_implementation
    {
        struct FlyoutHelpers : FlyoutHelpersT<FlyoutHelpers, implementation::FlyoutHelpers>
        {
        };
    }

    I am getting the following error,

    Severity Code Description Project File Line Suppression State
    Error C2227 left of '->Release' must point to class/struct/union/generic type (compiling source file FlyoutHelpers.cpp) myapp C:\Users\wolf\source\repos\myapp\myapp\Generated Files\winrt\base.h 2581


    I'm not sure what left of '->Release' here is trying to tell me
    Tuesday, November 19, 2019 3:00 PM
  • Hi,

    There are some grammatical errors, like e.NewValue().as<bool>();. We can't use as method  to convert IInspectable to bool, we need to use winrt::unbox_value, it's my fault, I misled you. And here is a simple sample I created that you can check it, I only create one button to operate it, when you want to put the button in listView, you need to change the viewmodel depending on the actual situation. Hope this could help you.

    By the way, We invite you to post new questions in the "Developing Universal Windows apps" forum’s new home on Microsoft Q&A (Preview)!

    Best Regards,

    Fay


    "Developing Universal Windows apps" forum will be migrating to a new home on Microsoft Q&A (Preview)!
    We invite you to post new questions in the "Developing Universal Windows apps" forum’s new home on Microsoft Q&A (Preview)!
    For more information, please refer to the sticky post.



    Wednesday, November 20, 2019 8:58 AM
  • I was able to adapt this into a collection to work in my code. This is great example code that will help me understand how to better make custom attributes in the future.
    Wednesday, November 20, 2019 2:19 PM