Wykorzystanie komend
This commit is contained in:
parent
879c29cc74
commit
093b590ee4
@ -23,6 +23,7 @@
|
|||||||
<e p="MainWindow.xaml" t="Include" />
|
<e p="MainWindow.xaml" t="Include" />
|
||||||
<e p="MainWindow.xaml.cs" t="Include" />
|
<e p="MainWindow.xaml.cs" t="Include" />
|
||||||
<e p="Misc" t="Include">
|
<e p="Misc" t="Include">
|
||||||
|
<e p="DelegateCommand.cs" t="Include" />
|
||||||
<e p="DelegateSubscriber.cs" t="Include" />
|
<e p="DelegateSubscriber.cs" t="Include" />
|
||||||
<e p="DelegateUnsubscriber.cs" t="Include" />
|
<e p="DelegateUnsubscriber.cs" t="Include" />
|
||||||
<e p="Position.cs" t="Include" />
|
<e p="Position.cs" t="Include" />
|
||||||
@ -36,6 +37,7 @@
|
|||||||
</e>
|
</e>
|
||||||
</e>
|
</e>
|
||||||
<e p="ViewModel" t="Include">
|
<e p="ViewModel" t="Include">
|
||||||
|
<e p="AutomatonViewModel.cs" t="Include" />
|
||||||
<e p="BaseViewModel.cs" t="Include" />
|
<e p="BaseViewModel.cs" t="Include" />
|
||||||
<e p="CellViewModel.cs" t="Include" />
|
<e p="CellViewModel.cs" t="Include" />
|
||||||
<e p="FieldViewModel.cs" t="Include" />
|
<e p="FieldViewModel.cs" t="Include" />
|
||||||
|
@ -46,6 +46,11 @@ namespace Life.Automaton
|
|||||||
_observers.ForEach(observer => observer.OnNext(this));
|
_observers.ForEach(observer => observer.OnNext(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Notify()
|
||||||
|
{
|
||||||
|
_observers.ForEach(observer => observer.OnNext(this));
|
||||||
|
}
|
||||||
|
|
||||||
public event PropertyChangedEventHandler PropertyChanged;
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
[NotifyPropertyChangedInvocator]
|
[NotifyPropertyChangedInvocator]
|
||||||
|
@ -2,9 +2,14 @@
|
|||||||
|
|
||||||
namespace Life.Automaton
|
namespace Life.Automaton
|
||||||
{
|
{
|
||||||
public static class GameOfLife
|
public class GameOfLife : IAutomaton
|
||||||
{
|
{
|
||||||
public static Rule Rule(string born, string survive)
|
public GameOfLife(int width, int height)
|
||||||
|
{
|
||||||
|
Initialize(new MooreField(width, height));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Rule MakeRule(string born, string survive)
|
||||||
{
|
{
|
||||||
bool WillSurvive(int neighbours) => survive.Contains(neighbours.ToString());
|
bool WillSurvive(int neighbours) => survive.Contains(neighbours.ToString());
|
||||||
bool WillBorn(int neighbours) => born.Contains(neighbours.ToString());
|
bool WillBorn(int neighbours) => born.Contains(neighbours.ToString());
|
||||||
@ -29,5 +34,22 @@ namespace Life.Automaton
|
|||||||
return @new;
|
return @new;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Rule Rule { get; set; } = MakeRule("3", "32");
|
||||||
|
|
||||||
|
public int Iteration { get; private set; }
|
||||||
|
|
||||||
|
public IField Field { get; private set; }
|
||||||
|
|
||||||
|
public void Initialize(IField field)
|
||||||
|
{
|
||||||
|
Field = field;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Advance()
|
||||||
|
{
|
||||||
|
Field.Transform(Rule);
|
||||||
|
Iteration++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -17,5 +17,6 @@ namespace Life.Automaton
|
|||||||
IEnumerable<Cell> Neighbours(int x, int y);
|
IEnumerable<Cell> Neighbours(int x, int y);
|
||||||
|
|
||||||
void Transform(Rule rule);
|
void Transform(Rule rule);
|
||||||
|
void Notify();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -47,7 +47,7 @@
|
|||||||
<Setter.Value>
|
<Setter.Value>
|
||||||
<ControlTemplate TargetType="Button">
|
<ControlTemplate TargetType="Button">
|
||||||
<Border x:Name="Border"
|
<Border x:Name="Border"
|
||||||
BorderThickness="1"
|
BorderThickness="{TemplateBinding BorderThickness}"
|
||||||
Background="{TemplateBinding Background}"
|
Background="{TemplateBinding Background}"
|
||||||
BorderBrush="{TemplateBinding BorderBrush}">
|
BorderBrush="{TemplateBinding BorderBrush}">
|
||||||
<ContentPresenter Margin="2"
|
<ContentPresenter Margin="2"
|
||||||
@ -73,8 +73,9 @@
|
|||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Button Width="{Binding Size, RelativeSource={RelativeSource AncestorType={x:Type local:AutomatonField}}}"
|
<Button Width="{Binding Size, RelativeSource={RelativeSource AncestorType={x:Type local:AutomatonField}}}"
|
||||||
Height="{Binding Size, RelativeSource={RelativeSource AncestorType={x:Type local:AutomatonField}}}"
|
Height="{Binding Size, RelativeSource={RelativeSource AncestorType={x:Type local:AutomatonField}}}"
|
||||||
Click="Cell_Click"
|
|
||||||
Style="{DynamicResource Cell}"
|
Style="{DynamicResource Cell}"
|
||||||
|
Command="{Binding ClickCommand, RelativeSource={RelativeSource AncestorType={x:Type local:AutomatonField}}}"
|
||||||
|
CommandParameter="{Binding Position}"
|
||||||
/>
|
/>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ItemsControl.ItemTemplate>
|
</ItemsControl.ItemTemplate>
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
using System;
|
using System.Windows;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Media;
|
using System.Windows.Input;
|
||||||
using System.Windows.Shapes;
|
|
||||||
using Life.Automaton;
|
using Life.Automaton;
|
||||||
using Life.ViewModel;
|
using Life.ViewModel;
|
||||||
|
|
||||||
@ -29,6 +26,12 @@ namespace Life
|
|||||||
get { return (IField) GetValue(FieldProperty); }
|
get { return (IField) GetValue(FieldProperty); }
|
||||||
set { SetValue(FieldProperty, value); }
|
set { SetValue(FieldProperty, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ICommand ClickCommand
|
||||||
|
{
|
||||||
|
get { return (ICommand) GetValue(ClickCommandProperty); }
|
||||||
|
set { SetValue(ClickCommandProperty, value); }
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public FieldViewModel ViewModel { get; set; } = new FieldViewModel();
|
public FieldViewModel ViewModel { get; set; } = new FieldViewModel();
|
||||||
@ -77,16 +80,12 @@ namespace Life
|
|||||||
typeof(IField), typeof(AutomatonField),
|
typeof(IField), typeof(AutomatonField),
|
||||||
new PropertyMetadata(OnFieldChanged)
|
new PropertyMetadata(OnFieldChanged)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
public static readonly DependencyProperty ClickCommandProperty = DependencyProperty.Register(
|
||||||
|
nameof(ClickCommand),
|
||||||
|
typeof(ICommand), typeof(AutomatonField)
|
||||||
|
);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private void Cell_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
var vm = (sender as Button).DataContext as CellViewModel;
|
|
||||||
var cell = Field[vm.Position.X, vm.Position.Y];
|
|
||||||
|
|
||||||
cell.IsAlive = !cell.IsAlive;
|
|
||||||
|
|
||||||
ViewModel.Sync();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,17 +4,18 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:local="clr-namespace:Life"
|
xmlns:local="clr-namespace:Life"
|
||||||
|
xmlns:vm="clr-namespace:Life.ViewModel"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Title="MainWindow" Height="450" Width="800" d:DataContext="{d:DesignInstance local:MainWindow}">
|
Title="MainWindow" Height="450" Width="800" d:DataContext="{d:DesignInstance vm:AutomatonViewModel}">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="2*" MinWidth="400"/>
|
<ColumnDefinition Width="2*" MinWidth="400"/>
|
||||||
<ColumnDefinition Width="3"/>
|
<ColumnDefinition Width="3"/>
|
||||||
<ColumnDefinition Width="1*" MinWidth="250"/>
|
<ColumnDefinition Width="1*" MinWidth="300" MaxWidth="400"/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
||||||
<local:AutomatonField Field="{Binding Field}" Size="{Binding Size}" Separation="3"/>
|
<local:AutomatonField Field="{Binding Field}" Size="{Binding Size}" Separation="3" ClickCommand="{Binding CellClicked}"/>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
|
|
||||||
<GridSplitter Grid.Column="1" Width="3" ResizeDirection="Columns" ResizeBehavior="PreviousAndNext"/>
|
<GridSplitter Grid.Column="1" Width="3" ResizeDirection="Columns" ResizeBehavior="PreviousAndNext"/>
|
||||||
@ -31,8 +32,7 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<StackPanel Orientation="Vertical" Grid.Row="1" VerticalAlignment="Bottom">
|
<StackPanel Orientation="Vertical" Grid.Row="1" VerticalAlignment="Bottom">
|
||||||
<Button VerticalAlignment="Stretch" Margin="0 0 0 8">Step</Button>
|
<Button VerticalAlignment="Stretch" Command="{Binding StepCommand}">Step</Button>
|
||||||
<Button VerticalAlignment="Stretch" Click="Step_OnClick">Step</Button>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -1,63 +1,28 @@
|
|||||||
using System;
|
using System.Windows;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Windows;
|
|
||||||
using Life.Annotations;
|
|
||||||
using Life.Automaton;
|
using Life.Automaton;
|
||||||
|
using Life.ViewModel;
|
||||||
|
|
||||||
namespace Life
|
namespace Life
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interaction logic for MainWindow.xaml
|
/// Interaction logic for MainWindow.xaml
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class MainWindow : Window, INotifyPropertyChanged
|
public partial class MainWindow : Window
|
||||||
{
|
{
|
||||||
private IField _field;
|
public AutomatonViewModel ViewModel;
|
||||||
private int _size;
|
|
||||||
private Rule _rule = GameOfLife.Rule("3", "23");
|
|
||||||
|
|
||||||
public IField Field
|
|
||||||
{
|
|
||||||
get => _field;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_field = value;
|
|
||||||
OnPropertyChanged(nameof(Field));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Size
|
|
||||||
{
|
|
||||||
get => _size;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_size = value;
|
|
||||||
OnPropertyChanged(nameof(Size));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public MainWindow()
|
public MainWindow()
|
||||||
{
|
{
|
||||||
Size = 20;
|
ViewModel = new AutomatonViewModel()
|
||||||
Field = new MooreField(20, 20);
|
{
|
||||||
Field[5, 5].IsAlive = true;
|
Automaton = new GameOfLife(20, 20),
|
||||||
DataContext = this;
|
Size = 16,
|
||||||
|
Separation = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
DataContext = ViewModel;
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Step_OnClick(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
Field.Transform(_rule);
|
|
||||||
}
|
|
||||||
|
|
||||||
public event PropertyChangedEventHandler PropertyChanged;
|
|
||||||
|
|
||||||
[NotifyPropertyChangedInvocator]
|
|
||||||
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
|
||||||
{
|
|
||||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
26
Life/Misc/DelegateCommand.cs
Normal file
26
Life/Misc/DelegateCommand.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using System;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace Life.Misc
|
||||||
|
{
|
||||||
|
public class DelegateCommand<T> : ICommand
|
||||||
|
{
|
||||||
|
public Action<T> Action { get; set; }
|
||||||
|
public Predicate<T> Predicate { get; set; }
|
||||||
|
|
||||||
|
public bool CanExecute(object parameter)
|
||||||
|
{
|
||||||
|
if (Action == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return Predicate?.Invoke((T) parameter) ?? true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Execute(object parameter)
|
||||||
|
{
|
||||||
|
Action?.Invoke((T)parameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler CanExecuteChanged;
|
||||||
|
}
|
||||||
|
}
|
70
Life/ViewModel/AutomatonViewModel.cs
Normal file
70
Life/ViewModel/AutomatonViewModel.cs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
using System;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using Life.Automaton;
|
||||||
|
using Life.Misc;
|
||||||
|
|
||||||
|
namespace Life.ViewModel
|
||||||
|
{
|
||||||
|
public class AutomatonViewModel : BaseViewModel
|
||||||
|
{
|
||||||
|
|
||||||
|
private int _size;
|
||||||
|
private int _separation;
|
||||||
|
private IAutomaton _automaton;
|
||||||
|
|
||||||
|
public int Size
|
||||||
|
{
|
||||||
|
get => _size;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_size = value;
|
||||||
|
OnPropertyChanged(nameof(Size));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Separation
|
||||||
|
{
|
||||||
|
get => _separation;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_separation = value;
|
||||||
|
OnPropertyChanged(nameof(Separation));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IAutomaton Automaton
|
||||||
|
{
|
||||||
|
get => _automaton;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_automaton = value;
|
||||||
|
OnPropertyChanged(nameof(Field));
|
||||||
|
OnPropertyChanged(nameof(Iteration));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IField Field => Automaton.Field;
|
||||||
|
public int Iteration => Automaton.Iteration;
|
||||||
|
|
||||||
|
public ICommand CellClicked => new DelegateCommand<Position>
|
||||||
|
{
|
||||||
|
Action = HandleCellClick
|
||||||
|
};
|
||||||
|
|
||||||
|
public ICommand StepCommand => new DelegateCommand<object>
|
||||||
|
{
|
||||||
|
Action = Step
|
||||||
|
};
|
||||||
|
|
||||||
|
private void Step(object param)
|
||||||
|
{
|
||||||
|
Automaton.Advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleCellClick(Position position)
|
||||||
|
{
|
||||||
|
Field[position.X, position.Y].IsAlive = !Field[position.X, position.Y].IsAlive;
|
||||||
|
Field.Notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user