单击按钮时隐藏弹出按钮 (DelegateCommand)
Hide Flyout on button click (DelegateCommand)
我正在构建一个 Windows 应用商店应用程序,我有一个如下所示的弹出窗口:
Flyout
功能正常,点击"Add"Button
可以添加新地址。问题是,我也希望能够隐藏 Flyout
。我的 DelegateCommand
在 ViewModel
中,所以我没有对实际 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" Button
是 Flyout
的子项,它附加到 "Add Address" AppBarButton
.
理想情况下,我可以直接传递对 Flyout
或 AppBarButton
的引用,这样我就可以在单击 "Add" 时调用 Flyout.Hide()
] 按钮`.
我尝试设置 AppBarButton
的 x:Name
和 Flyout
并在 CommandParameter
中引用它们,如下所示:
CommandParameter="{Binding ElementName=AddAddressFlyout}"
在这两种情况下,我的参数都是 null
。是否可以使用直接数据绑定来完成此操作,或者我是否必须添加某种 Behavior
s?
您可能会发现这篇文章很有用,它演示了如何使用依赖项 属性 来控制弹出窗口是打开还是关闭。然后,您可以将依赖项 属性 绑定到视图模型上的 属性: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>
我正在构建一个 Windows 应用商店应用程序,我有一个如下所示的弹出窗口:
Flyout
功能正常,点击"Add"Button
可以添加新地址。问题是,我也希望能够隐藏 Flyout
。我的 DelegateCommand
在 ViewModel
中,所以我没有对实际 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" Button
是 Flyout
的子项,它附加到 "Add Address" AppBarButton
.
理想情况下,我可以直接传递对 Flyout
或 AppBarButton
的引用,这样我就可以在单击 "Add" 时调用 Flyout.Hide()
] 按钮`.
我尝试设置 AppBarButton
的 x:Name
和 Flyout
并在 CommandParameter
中引用它们,如下所示:
CommandParameter="{Binding ElementName=AddAddressFlyout}"
在这两种情况下,我的参数都是 null
。是否可以使用直接数据绑定来完成此操作,或者我是否必须添加某种 Behavior
s?
您可能会发现这篇文章很有用,它演示了如何使用依赖项 属性 来控制弹出窗口是打开还是关闭。然后,您可以将依赖项 属性 绑定到视图模型上的 属性: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()
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>