我是WPF和C#开发的新手,并且正在开发此应用程序。我不知道是否有人熟悉VOIP App Discord,但他们有我真正喜欢的特定行为,并想尝试使用WPF创建类似的样式。
在Discord上添加服务器时,单击一个按钮,整个后窗口消失,并且在前台打开一个新窗口,提示您添加服务器。在窗口外部单击会导致该窗口在背景窗口关闭并重新聚焦。
无论如何,这是一个GIF来帮助证明这种特定行为(忽略星星,不想泄露个人信息)。
https://i.imgur.com/cn0sFlO.gifv
我真的很陌生,所以不知道如何模仿这种行为。
答案 0 :(得分:2)
这是一个自定义的Flyout控件,您可以使用它并对其进行操作,就像您要查找的一样。
以下内容将向您展示如何编写和使用自定义Flyout,就像这样:
<Window.Resources>
<local:FlyoutControl x:Key="CustomFlyout">
<Grid Width="400" Height="200" Background="PeachPuff">
<TextBlock Text="Inside Flyout" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
</local:FlyoutControl>
</Window.Resources>
<Grid>
<Button Content="I have a flyout"
Width="120"
Height="40"
local:FlyoutAttach.Flyout="{StaticResource CustomFlyout}"/>
</Grid>
我看到您已经有了一个答案,但是当我看到问题时我就开始构建它,因此,如果您想使用它并以自己的意愿使用它,那很好。自从我做出努力以来,我想我也会分享这个答案。
我建议更进一步,并添加一个AttachableProperty,该属性可用于将Flyout附加到UWP应用程序中的按钮之类的控件上。在AP中,您可以找到MainWindow并将其添加到网格的底部并自动显示。但是,这假定MainWindow具有Grid的根面板。编辑:我还添加了一个可附加属性以供参考。
FlyoutControl.xaml
<ContentControl x:Name="ContentControl"
x:Class="Question_Answer_WPF_App.FlyoutControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Template="{DynamicResource ContentControlTemplate}"
Opacity="0"
Visibility="Hidden">
<ContentControl.Resources>
<Duration x:Key="OpenDuration">00:00:00.4</Duration>
<Storyboard x:Key="OpenStoryboard" Duration="{StaticResource OpenDuration}">
<DoubleAnimation Storyboard.TargetName="ContentControl" Storyboard.TargetProperty="Opacity" To="1" Duration="{StaticResource OpenDuration}">
<DoubleAnimation.EasingFunction>
<BackEase EasingMode="EaseOut" Amplitude="0.4"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentControl" Storyboard.TargetProperty="Visibility" Duration="{StaticResource OpenDuration}">
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Visible}" KeyTime="00:00:00" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="OpenInnerContentStoryboard" Duration="{StaticResource OpenDuration}">
<DoubleAnimation Storyboard.TargetName="scaleTransform" Storyboard.TargetProperty="ScaleX" To="1" Duration="{StaticResource OpenDuration}">
<DoubleAnimation.EasingFunction>
<BackEase EasingMode="EaseOut" Amplitude="0.4"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation Storyboard.TargetName="scaleTransform" Storyboard.TargetProperty="ScaleY" To="1" Duration="{StaticResource OpenDuration}">
<DoubleAnimation.EasingFunction>
<BackEase EasingMode="EaseOut" Amplitude="0.4"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
<Storyboard x:Key="CloseStoryboard">
<DoubleAnimation Storyboard.TargetName="ContentControl" Storyboard.TargetProperty="Opacity" To="0" Duration="00:00:00"/>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentControl" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Hidden}" KeyTime="00:00:00" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="CloseInnerContentStoryboard">
<DoubleAnimation Storyboard.TargetName="scaleTransform" Storyboard.TargetProperty="ScaleX" To="0" Duration="00:00:00"/>
<DoubleAnimation Storyboard.TargetName="scaleTransform" Storyboard.TargetProperty="ScaleY" To="0" Duration="00:00:00"/>
</Storyboard>
<ControlTemplate x:Key="InnerContentButtonTemplate" TargetType="Button">
<ContentPresenter />
</ControlTemplate>
<ControlTemplate x:Key="BackgroundButtonTemplate" TargetType="Button">
<Grid Background="Black">
<Button VerticalAlignment="Center" HorizontalAlignment="Center" Click="InnerContentButtonClick" Template="{StaticResource InnerContentButtonTemplate}">
<ContentPresenter />
</Button>
</Grid>
</ControlTemplate>
<ControlTemplate x:Key="ContentControlTemplate" TargetType="ContentControl">
<Button x:Name="BackgroundButton" Template="{StaticResource BackgroundButtonTemplate}" Background="#B2000000" Click="BackgroundButtonClick">
<ContentPresenter RenderTransformOrigin="0.5, 0.5">
<ContentPresenter.RenderTransform>
<ScaleTransform x:Name="scaleTransform" ScaleX="0" ScaleY="0"/>
</ContentPresenter.RenderTransform>
</ContentPresenter>
</Button>
</ControlTemplate>
</ContentControl.Resources>
</ContentControl>
FlyoutControl.xaml.cs
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Animation;
namespace Question_Answer_WPF_App
{
public partial class FlyoutControl : ContentControl
{
public FlyoutControl() => InitializeComponent();
private void OpenFlyout()
{
var openStoryboard = Resources["OpenStoryboard"] as Storyboard;
var openInnerContentStoryboard = Resources["OpenInnerContentStoryboard"] as Storyboard;
openStoryboard.Begin();
openInnerContentStoryboard.Begin(this, Template);
}
private void CloseFlyout()
{
var closeStoryboard = Resources["CloseStoryboard"] as Storyboard;
var closeInnerContentStoryboard = Resources["CloseInnerContentStoryboard"] as Storyboard;
closeStoryboard.Begin();
closeInnerContentStoryboard.Begin(this, Template);
}
public bool IsOpen
{
get { return (bool)GetValue(IsOpenProperty); }
set { SetValue(IsOpenProperty, value); }
}
public static readonly DependencyProperty IsOpenProperty =
DependencyProperty.Register(nameof(IsOpen),
typeof(bool),
typeof(FlyoutControl),
new PropertyMetadata(false,
new PropertyChangedCallback((s, e) =>
{
if (s is FlyoutControl flyoutControl && e.NewValue is bool boolean)
{
if (boolean)
{
flyoutControl.OpenFlyout();
}
else
{
flyoutControl.CloseFlyout();
}
}
})));
//Closes Flyout
private void BackgroundButtonClick(object sender, RoutedEventArgs e) => IsOpen = false;
//Disables clicks from within inner content from explicitly closing Flyout.
private void InnerContentButtonClick(object sender, RoutedEventArgs e) => e.Handled = true;
}
}
可以按如下方式使用:
<local:FlyoutControl>
<MyUserControlThatLooksLikeDiscord />
</local:FlyoutControl>
您可以手动或通过绑定进行控制,例如:
隐藏代码
flyoutControl.IsOpen = !flyoutControl.IsOpen;
XAML绑定
<Grid>
<local:FlyoutControl x:Name="flyoutControl">
<Grid Width="400" Height="200" Background="PeachPuff">
<TextBlock Text="Inside Flyout" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
</local:FlyoutControl>
<CheckBox IsChecked="{Binding IsOpen, ElementName=flyoutControl}" Content="Toggle Flyout" Margin="21" VerticalAlignment="Top" HorizontalAlignment="Left"/>
</Grid>
这是可附加的属性,以便您可以更像UWP应用程序那样使用它
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
namespace Question_Answer_WPF_App
{
public class FlyoutAttach
{
public static FlyoutControl GetFlyout(ButtonBase button)
=> (FlyoutControl)button.GetValue(FlyoutProperty);
public static void SetFlyout(ButtonBase button, FlyoutControl value)
=> button.SetValue(FlyoutProperty, value);
public static readonly DependencyProperty FlyoutProperty =
DependencyProperty.RegisterAttached("Flyout",
typeof(FlyoutControl),
typeof(FlyoutAttach),
new PropertyMetadata(null,
new PropertyChangedCallback((s, e) =>
{
if (s is ButtonBase button && e.NewValue is FlyoutControl newFlyout)
{
if (Application.Current.MainWindow.Content is Grid grid)
{
if (e.OldValue is FlyoutControl oldFlyout)
{
grid.Children.Remove(oldFlyout);
}
grid.Children.Add(newFlyout);
button.Click -= buttonClick;
button.Click += buttonClick;
}
else
{
throw new Exception($"{nameof(Application.Current.MainWindow)} must have a root layout panel of type {nameof(Grid)} in order to use attachable Flyout.");
}
void buttonClick(object sender, RoutedEventArgs routedEventArgs)
{
newFlyout.IsOpen = true;
}
}
})));
}
}
这很简单:
<Window.Resources>
<local:FlyoutControl x:Key="CustomFlyout" x:Name="flyoutControl">
<Grid Width="400" Height="200" Background="PeachPuff">
<TextBlock Text="Inside Flyout" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
</local:FlyoutControl>
</Window.Resources>
<Grid>
<Button Content="I have a flyout"
Width="120"
Height="40"
local:FlyoutAttach.Flyout="{StaticResource CustomFlyout}"/>
</Grid>
窗口
点击的按钮
答案 1 :(得分:0)
在XAML中:将Window
中的所有内容放入Grid
中。然后,当您想要在所有内容的顶部显示“新窗口”时,只需在最后的相同Grid
中添加控件即可。这将导致此新添加的控件显示在其他所有控件之上。
例如,如果您要淡出其他所有内容,请添加Canvas
,其背景为黑色,不透明度为0.5。您可以添加所需的任何内容,并以所需的任何方式设计“新窗口”。
如果要查看示例代码,请查看我在GitHub上的WPF库GM.WPF。它具有Dialogs正是您要实现的目标。另外,请查看test project,以查看正在使用的对话框。