問題描述

這是我第一次使用 non-rectangular 視窗和 WPF 中的動畫,所以當我正在處理所有與實際遊戲程式碼有關的錯誤時,我提交了 XAML 進行審查 – 我不喜歡多餘這是,但我相信有一個聰明的方式來簡化它。

<Window x:Class="SimonSays.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:simonSays="clr-namespace:SimonSays"
        mc:Ignorable="d"
        Height="480" Width="480" 
        AllowsTransparency="True" Background="Transparent" WindowStyle="None" 
        d:DataContext="{d:DesignInstance simonSays:SimonSaysRound}">
    <Window.Clip>
        <EllipseGeometry RadiusX="240" RadiusY="240" Center="242,242" />
    </Window.Clip>
    <Border Background="Black" BorderThickness="2">
        <Border.Clip>
            <EllipseGeometry Center="240,240" RadiusX="238" RadiusY="238" />
        </Border.Clip>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>

            <StackPanel x:Name="MessageBar" Grid.Row="1" Grid.ColumnSpan="2" Margin="4" Height="0">
                <TextBlock x:Name="GameButton" Foreground="White" HorizontalAlignment="Center" FontSize="24" FontWeight="Bold" />
                <TextBlock x:Name="GameScoreLabel" Text="{Binding Score, StringFormat=Your score: {0}}" Foreground="White" HorizontalAlignment="Center" FontWeight="Bold" IsEnabled="False" />
            </StackPanel>

            <Border x:Name="Green" Margin="1" CornerRadius="16" MouseDown="Green_MouseDown">
                <Border.Clip>
                    <EllipseGeometry Center="240,240" RadiusX="240" RadiusY="240" />
                </Border.Clip>
                <Border.Style>
                    <Style>
                        <Setter Property="Border.Background">
                            <Setter.Value>
                                <RadialGradientBrush GradientOrigin="1,1" RadiusX="1" RadiusY="1">
                                    <GradientStop Color="LightGreen" Offset="0.0" />
                                    <GradientStop Color="DarkGreen" Offset="0.5" />
                                </RadialGradientBrush>
                            </Setter.Value>
                        </Setter>
                        <Style.Triggers>
                            <EventTrigger RoutedEvent="Border.MouseEnter">
                                <BeginStoryboard>
                                    <Storyboard TargetProperty="Background.GradientStops[1].Offset" Duration="0:0:0.25">
                                        <DoubleAnimation To="1.0" />
                                        <Storyboard TargetProperty="Background.GradientStops[0].Offset">
                                            <DoubleAnimation To="0.2" />
                                        </Storyboard>
                                    </Storyboard>
                                </BeginStoryboard>
                            </EventTrigger>
                            <EventTrigger RoutedEvent="Border.MouseLeave">
                                <BeginStoryboard>
                                    <Storyboard TargetProperty="Background.GradientStops[1].Offset" Duration="0:0:0.25">
                                        <DoubleAnimation To="0.5" />
                                        <Storyboard TargetProperty="Background.GradientStops[0].Offset">
                                            <DoubleAnimation To="0.0" />
                                        </Storyboard>
                                    </Storyboard>
                                </BeginStoryboard>
                            </EventTrigger>
                        </Style.Triggers>
                    </Style>
                </Border.Style>
            </Border>
            <Border Grid.Column="1" x:Name="Red" Margin="1" CornerRadius="16" MouseDown="Red_MouseDown">
                <Border.Clip>
                    <EllipseGeometry Center="-4,240" RadiusX="240" RadiusY="240" />
                </Border.Clip>
                <Border.Style>
                    <Style>
                        <Setter Property="Border.Background">
                            <Setter.Value>
                                <RadialGradientBrush GradientOrigin="0,1" RadiusX="1" RadiusY="1">
                                    <GradientStop Color="LightPink" Offset="0.0" />
                                    <GradientStop Color="DarkRed" Offset="0.5" />
                                </RadialGradientBrush>
                            </Setter.Value>
                        </Setter>
                        <Style.Triggers>
                            <EventTrigger RoutedEvent="Border.MouseEnter">
                                <BeginStoryboard>
                                    <Storyboard TargetProperty="Background.GradientStops[1].Offset" Duration="0:0:0.25">
                                        <DoubleAnimation To="1.0" />
                                        <Storyboard TargetProperty="Background.GradientStops[0].Offset">
                                            <DoubleAnimation To="0.2" />
                                        </Storyboard>
                                    </Storyboard>
                                </BeginStoryboard>
                            </EventTrigger>
                            <EventTrigger RoutedEvent="Border.MouseLeave">
                                <BeginStoryboard>
                                    <Storyboard TargetProperty="Background.GradientStops[1].Offset" Duration="0:0:0.25">
                                        <DoubleAnimation To="0.5" />
                                        <Storyboard TargetProperty="Background.GradientStops[0].Offset">
                                            <DoubleAnimation To="0.0" />
                                        </Storyboard>
                                    </Storyboard>
                                </BeginStoryboard>
                            </EventTrigger>
                        </Style.Triggers>
                    </Style>
                </Border.Style>
            </Border>
            <Border Grid.Row="2" x:Name="Yellow" Margin="1" CornerRadius="16" MouseDown="Yellow_MouseDown">
                <Border.Clip>
                    <EllipseGeometry Center="240,-4" RadiusX="240" RadiusY="240" />
                </Border.Clip>
                <Border.Style>
                    <Style>
                        <Setter Property="Border.Background">
                            <Setter.Value>
                                <RadialGradientBrush GradientOrigin="1,0" RadiusX="1" RadiusY="1">
                                    <GradientStop Color="LightYellow" Offset="0.0" />
                                    <GradientStop Color="Orange" Offset="0.5" />
                                </RadialGradientBrush>
                            </Setter.Value>
                        </Setter>
                        <Style.Triggers>
                            <EventTrigger RoutedEvent="Border.MouseEnter">
                                <BeginStoryboard>
                                    <Storyboard TargetProperty="Background.GradientStops[1].Offset" Duration="0:0:0.25">
                                        <DoubleAnimation To="1.0" />
                                        <Storyboard TargetProperty="Background.GradientStops[0].Offset">
                                            <DoubleAnimation To="0.2" />
                                        </Storyboard>
                                    </Storyboard>
                                </BeginStoryboard>
                            </EventTrigger>
                            <EventTrigger RoutedEvent="Border.MouseLeave">
                                <BeginStoryboard>
                                    <Storyboard TargetProperty="Background.GradientStops[1].Offset" Duration="0:0:0.25">
                                        <DoubleAnimation To="0.5" />
                                        <Storyboard TargetProperty="Background.GradientStops[0].Offset">
                                            <DoubleAnimation To="0.0" />
                                        </Storyboard>
                                    </Storyboard>
                                </BeginStoryboard>
                            </EventTrigger>
                        </Style.Triggers>
                    </Style>
                </Border.Style>
            </Border>
            <Border Grid.Row="2" Grid.Column="1" x:Name="Blue" Margin="1" CornerRadius="16" MouseDown="Blue_MouseDown">
                <Border.Clip>
                    <EllipseGeometry Center="-4,-4" RadiusX="240" RadiusY="240" />
                </Border.Clip>
                <Border.Style>
                    <Style>
                        <Setter Property="Border.Background">
                            <Setter.Value>
                                <RadialGradientBrush GradientOrigin="0,0" RadiusX="1" RadiusY="1">
                                    <GradientStop Color="LightSkyBlue" Offset="0.0" />
                                    <GradientStop Color="Blue" Offset="0.5" />
                                </RadialGradientBrush>
                            </Setter.Value>
                        </Setter>
                        <Style.Triggers>
                            <EventTrigger RoutedEvent="Border.MouseEnter">
                                <BeginStoryboard>
                                    <Storyboard TargetProperty="Background.GradientStops[1].Offset" Duration="0:0:0.25">
                                        <DoubleAnimation To="1.0" />
                                        <Storyboard TargetProperty="Background.GradientStops[0].Offset">
                                            <DoubleAnimation To="0.2" />
                                        </Storyboard>
                                    </Storyboard>
                                </BeginStoryboard>
                            </EventTrigger>
                            <EventTrigger RoutedEvent="Border.MouseLeave">
                                <BeginStoryboard>
                                    <Storyboard TargetProperty="Background.GradientStops[1].Offset" Duration="0:0:0.25">
                                        <DoubleAnimation To="0.5" />
                                        <Storyboard TargetProperty="Background.GradientStops[0].Offset">
                                            <DoubleAnimation To="0.0" />
                                        </Storyboard>
                                    </Storyboard>
                                </BeginStoryboard>
                            </EventTrigger>
                        </Style.Triggers>
                    </Style>
                </Border.Style>
            </Border>
        </Grid>
    </Border>
</Window>

結果是一個圓形視窗,四個象限和一個黑色的水平帶,用作拖動窗戶的手柄:

我也用它來顯示訊息,玩家的得分:

按鈕/象限在訊息頻段擴充套件 (無法單擊; 仍然對 mouse-over 做出反應) 時被停用,而 re-enabled 在點選訊息後崩潰。

沒有控制箱,視窗只能透過點選”Game Over” 標籤來關閉:

我在 code-behind 中有這個 C#程式碼 (還沒有準備好稽核的程式碼),用於動畫按鈕點選和訊息帶:

    private void AnimateMessageBand(double height)
    {
        var animation = new DoubleAnimation(height, new Duration(TimeSpan.FromMilliseconds(200)));
        RegisterName(MessageBar.Name, MessageBar);
        Storyboard.SetTargetName(animation, MessageBar.Name);
        Storyboard.SetTargetProperty(animation, new PropertyPath("Height"));
        var story = new Storyboard();
        story.Children.Add(animation);
        story.Begin(MessageBar);
        story.Remove();
    }

    private readonly IDictionary<SimonButton, Border> _buttons;

    public void HighlightSimonButton(SimonButton button)
    {
        var animation = new DoubleAnimation(0, 0.75, new Duration(TimeSpan.FromMilliseconds(100)));
        RegisterName(button.ToString(), _buttons[button]);
        Storyboard.SetTargetName(animation, button.ToString());
        Storyboard.SetTargetProperty(animation, new PropertyPath("Background.GradientStops[1].Offset"));
        var story = new Storyboard();
        story.Children.Add(animation);
        story.Begin(_buttons[button]);
        story.Remove();
    }

最佳解決方案

  1. 您可以使用 Border 建立一個按鈕,而不是使用具有自定義模板的實際 Button 類。因此,您必須手動管理已經在常規 Button(ClickedIsPressedCommand,與 IsEnabled 屬性和鍵盤等的互動) 中實現的所有互動。所以我建議你使用一個實際的按鈕。

  2. 那麼你的故事板顯然是 copy-pasted 。 :) 你為什麼不把他們移動到資源?

參考文獻

注:本文內容整合自 Google/Baidu/Bing 輔助翻譯的英文資料結果。如果您對結果不滿意,可以加入我們改善翻譯效果:薇曉朵技術論壇。