【问题标题】:Hide Flyout on button click (DelegateCommand)单击按钮时隐藏弹出按钮 (DelegateCommand)
【发布时间】:2015-02-26 06:38:04
【问题描述】:

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

Flyout 运行正常,当我单击“添加”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 的引用,但我无法引用树上的任何其他内容。 “添加”ButtonFlyout 的子代,附加到“添加地址”AppBarButton

理想情况下,我可以直接传递对FlyoutAppBarButton 的引用,以便在单击“添加”按钮时调用Flyout.Hide()

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

CommandParameter="{Binding ElementName=AddAddressFlyout}"

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

【问题讨论】:

    标签: c# xaml mvvm winrt-xaml windows-8.1


    【解决方案1】:

    也许我在您的要求中遗漏了一些细微之处,但我可以使用 x:Name 和 .Hide() 轻松关闭弹出窗口

    在您的&lt;Flyout&gt; 标签中使用 x:Name="MyFlyout",然后在您的 C# 点击事件中通过执行 MyFlyout.Hide() 将其关闭

    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();
        }
    }
    

    【讨论】:

    • 我不再为此使用Flyout 方法,但当时我试图避免使用代码隐藏,以坚持使用 MVVM 模式。
    • +1 添加快速事件并隐藏它更有意义,而不是添加几个类,然后为这么小的东西添加大量样板代码。
    【解决方案2】:

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

    我只是在我自己的应用程序中尝试过,效果很好。

    【讨论】:

    • 感谢您提供的信息,我自己为这篇文章添加了书签,以便以后尝试。如果可能的话,我希望能够让它直接绑定到FlyoutAppBarButton,就像我在原始问题中尝试的那样,但看来我可能不得不使用依赖属性路由。很高兴听到它对您有用,看来它应该可以解决问题!
    • 确实,它最终确实发挥了作用。现在确定它是否适用于同一 View 中的多个弹出窗口。我想应该是这样,因为一次不会看到多个......
    【解决方案3】:

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

    第二个附加到 Button 并引用 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>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多