网格动画(按钮颜色更改)

时间:2017-01-03 12:59:31

标签: c# wpf animation mouseover

我想在网格中创建一个动画。我有一个5x5网格,每个网格显示一个按钮。加载网格后,其中一个按钮应随意将其颜色更改为绿色。 1秒后,此按钮应更改回来,另一个按钮应将其颜色更改为绿色。

如果用户能够使用鼠标(鼠标悬停)在1秒内到达此按钮,则按钮应将其颜色更改为红色并保持红色。将颜色改为绿色的下一个按钮不应该是这个。

这应该是一个小游戏。我的问题是,实现这个游戏最简单的方法是什么。

请帮助我!

<Page x:Class="LeapTest.Layout"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
  xmlns:local="clr-namespace:LeapTest"
  mc:Ignorable="d" 
  d:DesignHeight="1050" d:DesignWidth="1000"
  Title="Layout">

<Page.Resources>
    <Style x:Key="pageTitle" TargetType="TextBlock">
        <Setter Property="Background" Value="DimGray"/>
        <Setter Property="FontSize"  Value="40"/>
        <Setter Property="FontFamily"  Value="Arial"/>
        <Setter Property="TextAlignment" Value="Center"/>
        <Setter Property="Padding" Value="0,5,0,5"/>
    </Style>

    <Style x:Key="Grid" TargetType="Grid">
        <Setter Property="Background" Value="White"/>
    </Style>

    <Style x:Key="Button" TargetType="Button">
        <Setter Property="Background" Value="White"/>
        <Setter Property="BorderBrush" Value="Green"/>
        <Setter Property="BorderThickness" Value="2"/>
    </Style>

</Page.Resources>

<Grid Style="{StaticResource Grid}">
    <Grid.RowDefinitions>
        <RowDefinition Height="50" />
        <RowDefinition Height="200" />
        <RowDefinition Height="200" />
        <RowDefinition Height="200" />
        <RowDefinition Height="200" />
        <RowDefinition Height="200" />
    </Grid.RowDefinitions>

    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="200" />
        <ColumnDefinition Width="200" />
        <ColumnDefinition Width="200" />
        <ColumnDefinition Width="200" />
        <ColumnDefinition Width="200" />
    </Grid.ColumnDefinitions>

    <TextBlock Grid.Column="0" Grid.ColumnSpan="5" Style="{StaticResource pageTitle}"> LEAP Motion </TextBlock>

    <Button Name ="BTN_0_0" Grid.Column="0" Grid.Row="1" Click="BTN_Click" Style="{StaticResource Button}"/>
    <Button Name ="BTN_0_1" Grid.Column="1" Grid.Row="1" Click="BTN_Click" Style="{StaticResource Button}"/>
    <Button Name ="BTN_0_2" Grid.Column="2" Grid.Row="1" Click="BTN_Click" Style="{StaticResource Button}"/>
    <Button Name ="BTN_0_3" Grid.Column="3" Grid.Row="1" Click="BTN_Click" Style="{StaticResource Button}"/>
    <Button Name ="BTN_0_4" Grid.Column="4" Grid.Row="1" Click="BTN_Click" Style="{StaticResource Button}"/>

    <Button Name ="BTN_1_0" Grid.Column="0" Grid.Row="2" Click="BTN_Click" Style="{StaticResource Button}"/>
    <Button Name ="BTN_1_1" Grid.Column="1" Grid.Row="2" Click="BTN_Click" Style="{StaticResource Button}"/>
    <Button Name ="BTN_1_2" Grid.Column="2" Grid.Row="2" Click="BTN_Click" Style="{StaticResource Button}"/>
    <Button Name ="BTN_1_3" Grid.Column="3" Grid.Row="2" Click="BTN_Click" Style="{StaticResource Button}"/>
    <Button Name ="BTN_1_4" Grid.Column="4" Grid.Row="2" Click="BTN_Click" Style="{StaticResource Button}"/>

    <Button Name ="BTN_2_0" Grid.Column="0" Grid.Row="3" Click="BTN_Click" Style="{StaticResource Button}"/>
    <Button Name ="BTN_2_1" Grid.Column="1" Grid.Row="3" Click="BTN_Click" Style="{StaticResource Button}"/>
    <Button Name ="BTN_2_2" Grid.Column="2" Grid.Row="3" Click="BTN_Click" Style="{StaticResource Button}"/>
    <Button Name ="BTN_2_3" Grid.Column="3" Grid.Row="3" Click="BTN_Click" Style="{StaticResource Button}"/>
    <Button Name ="BTN_2_4" Grid.Column="4" Grid.Row="3" Click="BTN_Click" Style="{StaticResource Button}"/>

    <Button Name ="BTN_3_0" Grid.Column="0" Grid.Row="4" Click="BTN_Click" Style="{StaticResource Button}"/>
    <Button Name ="BTN_3_1" Grid.Column="1" Grid.Row="4" Click="BTN_Click" Style="{StaticResource Button}"/>
    <Button Name ="BTN_3_2" Grid.Column="2" Grid.Row="4" Click="BTN_Click" Style="{StaticResource Button}"/>
    <Button Name ="BTN_3_3" Grid.Column="3" Grid.Row="4" Click="BTN_Click" Style="{StaticResource Button}"/>
    <Button Name ="BTN_3_4" Grid.Column="4" Grid.Row="4" Click="BTN_Click" Style="{StaticResource Button}"/>

    <Button Name ="BTN_4_0" Grid.Column="0" Grid.Row="5" Click="BTN_Click" Style="{StaticResource Button}"/>
    <Button Name ="BTN_4_1" Grid.Column="1" Grid.Row="5" Click="BTN_Click" Style="{StaticResource Button}"/>
    <Button Name ="BTN_4_2" Grid.Column="2" Grid.Row="5" Click="BTN_Click" Style="{StaticResource Button}"/>
    <Button Name ="BTN_4_3" Grid.Column="3" Grid.Row="5" Click="BTN_Click" Style="{StaticResource Button}"/>
    <Button Name ="BTN_4_4" Grid.Column="4" Grid.Row="5" Click="BTN_Click" Style="{StaticResource Button}"/>

</Grid>

//BackEnd Code
      private void BTN_Click(object sender, RoutedEventArgs e)
    {
        //BTN1.Background = Brushes.Green;

        Button btnTest = (Button)sender;
        if (btnTest.Background == Brushes.Green)
        {
            btnTest.Background = Brushes.White;
        }
        else
        {
            btnTest.Background = Brushes.Green;
        }
    }

2 个答案:

答案 0 :(得分:0)

您应该使用特殊名称或标记遍历表单上的所有按钮控件。将其保存在数组中并随机选择一个并更改其颜色。如果鼠标悬停找到具有正确颜色的那个,则调用该方法以随机查找控件,依此类推。

这应该是非常直截了当的。因为这看起来像家庭作业。我不会为你解决,因为你不会学到任何东西。考虑需要做什么,并分别谷歌各个部分。试着理解它,然后继续!好运!

答案 1 :(得分:0)

编辑:严格按照你的问题,你不需要动画来实现你想做的事情,除非你需要动画颜色变化。

这是一个完整的工作示例不使用MVVM ,而是使用代表按钮的模型集合。

主窗口/页面代码处理所有逻辑(随机,模型更改等):

public partial class MainWindow : Window, INotifyPropertyChanged
{
    private const int BTN_NUMBERS = 25;
    private ObservableCollection<ButtonModel> _buttonsCollection;
    private ButtonModel _currentTarget;

    public ObservableCollection<int> ExcludedItems
    {
        get { return _excludedItems; }
        private set { _excludedItems = value; OnPropertyChanged(); }
    }

    private Random _rnd;
    private Timer _timer;
    private ObservableCollection<int> _excludedItems = new ObservableCollection<int>();

    public MainWindow()
    {
        DataContext = this;

        InitializeComponent();
        ButtonsCollection = new ObservableCollection<ButtonModel>();
        for (int i = 0; i < BTN_NUMBERS; i++)
        {
            ButtonsCollection.Add(new ButtonModel() { ButtonNumber = i });
        }

        Start();
    }

    private void Start()
    {
        _currentTarget = null;
        foreach (var bm in ButtonsCollection)
        {
            bm.IsCurrentTarget = bm.IsReached = false;
        }
        ExcludedItems.Clear();
        _rnd = new Random(DateTime.Now.Second);
        _timer = new Timer(OnTargetChanged, null, 0, 1000);
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public ObservableCollection<ButtonModel> ButtonsCollection
    {
        get { return _buttonsCollection; }
        set { _buttonsCollection = value; OnPropertyChanged(); }
    }

    void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    private void Btn_candidate_OnMouseEnter(object sender, MouseEventArgs e)
    {
        ButtonModel model = ((Button)sender).DataContext as ButtonModel;
        if (model != null && model.IsCurrentTarget && !ExcludedItems.Contains(model.ButtonNumber))
        {
            model.IsReached = true;
            ExcludedItems.Add(model.ButtonNumber);
        }
    }

    private void ChangeTarget()
    {
        var target = GetNextTarget();
        if (target == -1)
        {

            if (_timer != null)
            {
                _timer.Dispose();
                _timer = null;
            }
            MessageBox.Show("All items have been reached ! Congratulations");
        }
        if (_currentTarget != null) _currentTarget.IsCurrentTarget = false;
        _currentTarget = ButtonsCollection[target];
        _currentTarget.IsCurrentTarget = true;
    }

    private int GetNextTarget()
    {
        if (ExcludedItems.Count == BTN_NUMBERS)
        {
            return -1;
        }
        var target = _rnd.Next(0, BTN_NUMBERS);
        if (ExcludedItems.Contains(target))
        {
            return GetNextTarget();
        }
        return target;
    }

    private void OnTargetChanged(object state)
    {
        this.Dispatcher.InvokeAsync(ChangeTarget);
    }

    private void Btn_startover_OnClick(object sender, RoutedEventArgs e)
    {
        Start();
    }
}

表示按钮的模型,其中包含触发XAML更改的代码:

    public class ButtonModel : INotifyPropertyChanged
{
    private bool _isCurrentTarget;
    private bool _isReached;

    public event PropertyChangedEventHandler PropertyChanged;

    public int ButtonNumber { get; set; }

    public bool IsCurrentTarget
    {
        get { return _isCurrentTarget; }
        set { _isCurrentTarget = value; OnPropertyChanged(); }
    }

    public bool IsReached
    {
        get { return _isReached; }
        set { _isReached = value; OnPropertyChanged(); }
    }

    private void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

最后,最重要的是,简化的XAML代码:

<Window x:Class="GridAnimame.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:local="clr-namespace:GridAnimame"
    mc:Ignorable="d"
    d:DataContext="{d:DesignInstance {x:Type local:MainWindow}}"
    Title="MainWindow" Height="500" Width="500">
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="400"/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="400"/>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <ItemsControl ItemsSource="{Binding ButtonsCollection}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <UniformGrid />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Button Name="btn_candidate"  MouseEnter="Btn_candidate_OnMouseEnter" Margin="1">
                    <Button.Template>
                        <ControlTemplate TargetType="Button">
                            <Border x:Name="brd_btn_layout" Background="LightGray" BorderBrush="Black" BorderThickness="1">
                                <TextBlock Text="{Binding ButtonNumber}" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="Black"></TextBlock>
                            </Border>
                            <ControlTemplate.Triggers>
                                <DataTrigger Binding="{Binding IsCurrentTarget}" Value="true">
                                    <Setter TargetName="brd_btn_layout" Property="Background" Value="Green"></Setter>
                                </DataTrigger>
                                <DataTrigger Binding="{Binding IsReached}" Value="true">
                                    <Setter TargetName="brd_btn_layout" Property="Background" Value="Red"></Setter>
                                </DataTrigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Button.Template>
                </Button>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>

    <ListBox Grid.Row="0" Grid.Column="1" ItemsSource="{Binding ExcludedItems}"></ListBox>

    <Button x:Name="btn_startover" Grid.Row="1" Grid.Column="1" Content="Start Over !" Margin="2" Click="Btn_startover_OnClick"></Button>
</Grid>

虽然可以改进逻辑,但以下是此示例的关键点:

  • 您不会在XAML中以静态方式声明所有按钮。相反,您的主模型包含一组模型,这些模型表示按钮并包含将触发XAML(可视)更改的所有数据。因此,表示网格的XAML中的控件绑定到此集合

  • 逻辑是通过代码完成的,使用XAML中声明的触发器反映了这种逻辑的视觉效果

  • 为了采用干净的方法,仍然只需做2件事:1)现在可以轻松地将主窗口逻辑封装到真实视图模型中,该模型将用作窗口数据上下文和2)事件应由DelegateCommands

  • 替换