单击按钮时隐藏弹出按钮 (DelegateCommand)

Hide Flyout on button click (DelegateCommand)

我正在构建一个 Windows 应用商店应用程序,我有一个如下所示的弹出窗口:

Flyout功能正常,点击"Add"Button可以添加新地址。问题是,我也希望能够隐藏 Flyout。我的 DelegateCommandViewModel 中,所以我没有对实际 View 元素的引用。

我试过更改 DelegateCommand 以获取参数,如下所示:

public DelegateCommand<object> AddAddressCommand
{
    get { return new DelegateCommand<object>(AddAddress, CanAddAddress); }
}

public void AddAddress(object parameter)
{
    if (_isEditing)
    {
        NewAddress.PayeeId = CurrentPayee.Id;
        _addressRepository.InsertAsync(NewAddress);
    }
    CurrentPayee.Addresses.Add(NewAddress);
    NewAddress = new Address();

    // TODO: hide Flyout
}

在我的 XAML 中,我尝试像这样将 CommandParameter 传递给 DelegateCommand

<Button Content="Add" 
        Command="{Binding AddAddressCommand}"
        CommandParameter="{Binding RelativeSource={RelativeSource Self}}"
        HorizontalAlignment="Center" />

如果我通过 {RelativeSource Self},我会按预期获得对 Button 的引用,但我无法引用树上的任何其他内容。 "Add" ButtonFlyout 的子项,它附加到 "Add Address" AppBarButton.

理想情况下,我可以直接传递对 FlyoutAppBarButton 的引用,这样我就可以在单击 "Add" 时调用 Flyout.Hide() ] 按钮`.

我尝试设置 AppBarButtonx:NameFlyout 并在 CommandParameter 中引用它们,如下所示:

CommandParameter="{Binding ElementName=AddAddressFlyout}"

在这两种情况下,我的参数都是 null。是否可以使用直接数据绑定来完成此操作,或者我是否必须添加某种 Behaviors?

您可能会发现这篇文章很有用,它演示了如何使用依赖项 属性 来控制弹出窗口是打开还是关闭。然后,您可以将依赖项 属性 绑定到视图模型上的 属性:https://marcominerva.wordpress.com/2013/07/30/using-windows-8-1-flyout-xaml-control-with-mvvm/

我真的只是在我自己的应用程序中尝试过,它运行良好。

也许我在您的要求中遗漏了一个微妙之处,但我能够使用 x:Name 和 .Hide()

轻松关闭弹出窗口

在您的 <Flyout> 标记中使用 x:Name="MyFlyout",然后通过执行 MyFlyout.Hide()

在您的 C# 单击事件中关闭它

XAML 代码:

<Page.BottomAppBar>
    <CommandBar>
        <AppBarButton Icon="Add">
            <AppBarButton.Flyout>
                <Flyout x:Name="MyFlyout">
                    <StackPanel>
                        <Button HorizontalAlignment="Right" Click="CancelButton_Click" Margin="0,-10,-10,0">
                                <SymbolIcon Symbol="Cancel"/>
                        </Button>
                            <TextBlock>Hello World</TextBlock>
                            <TextBox></TextBox>
                    </StackPanel>
                </Flyout>
            </AppBarButton.Flyout>
        </AppBarButton>
    </CommandBar>
</Page.BottomAppBar>

C# 代码

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();
    }


    private void CancelButton_Click(object sender, RoutedEventArgs e)
    {
        MyFlyout.Hide();
    }
}

我建议使用 AttachableProperties。我将发送两个我编写的易于使用并实现此目标的。第一个附加到 Flyout 并引用一个 Button。单击该按钮后,它会关闭 Flyout。

第二个附加到按钮并引用 Flyout(如果 Flyout 中的按钮是数据模板的一部分则很有用)。只有在这种情况下才会出现相同的效果,您可以有多个按钮,按下这些按钮将关闭弹出按钮。

首先,我在示例中使用的项目中有自定义扩展方法:

public static class XAMLExtensions
{
    public static T GetParent<T>(this DependencyObject dependencyObject) where T : DependencyObject
    {
        var parentDependencyObject = VisualTreeHelper.GetParent(dependencyObject);

        switch (parentDependencyObject)
        {
            case null:
                return null;
            case T parent:
                return parent;
            default:
                return GetParent<T>(parentDependencyObject);
        }        
    }
}

然后附加属性... 附加属性

public class FlyoutAttach : DependencyObject
{
    private const string CloseButtonPropertyName = "CloseButton";
    private const string CanCloseFlyoutPropertyName = "CanCloseFlyout";
    private const string ClosedCommandPropertyName = "ClosedCommand";
    private const string ClosedCommandParameterPropertyName = "ClosedCommandParameter";

    public static Button GetCloseButton(Flyout flyout) => (Button)flyout.GetValue(CloseButtonProperty);
    public static void SetCloseButton(Flyout flyout, Button value) => flyout.SetValue(CloseButtonProperty, value);
    public static readonly DependencyProperty CloseButtonProperty =
        DependencyProperty.RegisterAttached(CloseButtonPropertyName,
                                            typeof(Button),
                                            typeof(FlyoutAttach),
                                            new PropertyMetadata(null,
                                            new PropertyChangedCallback((s, e) =>
                                            {
                                                if (s is Flyout flyout && e.NewValue is Button button)
                                                {
                                                    button.Click -= buttonClick;
                                                    button.Click += buttonClick;
                                                }
                                                void buttonClick(object sender, RoutedEventArgs routedEventArgs) => flyout.Hide();
                                            })));


    public static bool GetCanCloseFlyout(Button button) => (bool)button.GetValue(CanCloseFlyoutProperty);
    public static void SetCanCloseFlyout(Button button, bool value) => button.SetValue(CanCloseFlyoutProperty, value);
    public static readonly DependencyProperty CanCloseFlyoutProperty =
        DependencyProperty.RegisterAttached(CanCloseFlyoutPropertyName,
                                            typeof(bool),
                                            typeof(FlyoutAttach),
                                            new PropertyMetadata(false,
                                            new PropertyChangedCallback((s, e) =>
                                            {
                                                if (s is Button button && e.NewValue is bool canCloseFlyout)
                                                {
                                                    button.Click -= buttonClick;
                                                    if (canCloseFlyout) button.Click += buttonClick;
                                                }

                                                void buttonClick(object sender, RoutedEventArgs routedEventArgs)
                                                {
                                                    var flyoutPresenter = button.GetParent<FlyoutPresenter>();
                                                    if (flyoutPresenter?.Parent is Popup popup)
                                                        popup.IsOpen = false;
                                                }
                                            })));


    public static ICommand GetClosedCommand(Flyout flyout) => (ICommand)flyout.GetValue(ClosedCommandProperty);
    public static void SetClosedCommand(Flyout flyout, ICommand value) => flyout.SetValue(ClosedCommandProperty, value);
    public static readonly DependencyProperty ClosedCommandProperty =
        DependencyProperty.RegisterAttached(ClosedCommandPropertyName, 
                                            typeof(ICommand), 
                                            typeof(FlyoutAttach), 
                                            new PropertyMetadata(null,
                                            new PropertyChangedCallback((s, e) =>
                                            {
                                                if (s is Flyout flyout && e.NewValue is ICommand command)
                                                {
                                                    flyout.Closed -= flyoutClosed;
                                                    flyout.Closed += flyoutClosed;

                                                    void flyoutClosed(object sender, object ee)
                                                    {
                                                        var commandParameter = flyout.GetValue(ClosedCommandParameterProperty);
                                                        if (command.CanExecute(commandParameter))
                                                            command.Execute(commandParameter);
                                                    }
                                                }
                                            })));


    public static object GetClosedCommandParameter(Flyout flyout) => flyout.GetValue(ClosedCommandParameterProperty);
    public static void SetClosedCommandParameter(Flyout flyout, object value) => flyout.SetValue(ClosedCommandParameterProperty, value);
    public static readonly DependencyProperty ClosedCommandParameterProperty =
        DependencyProperty.RegisterAttached(ClosedCommandParameterPropertyName, typeof(object), typeof(FlyoutAttach), new PropertyMetadata(null));
}

在视图中

<Flyout Attachable:FlyoutAttach.CloseButton="{Binding ElementName=button}">
     <Button x:Name="button" />
</Flyout>

<Flyout>
     <Button Attachable:FlyoutAttach.CanCloseFlyout="True" />
</Flyout>