Ich verstehe jetzt was du meinst. Leider verstehe ich nicht wie man mit ItemsControl umgeht, aber das werd ich mir wohl einprügeln müssen.
Ich nutze auch ein Canvas. Die ItemsControl brauche ich, weil ich dann jedes einzelne Item individuell behandeln muss. Mit Margin=0 bleibt das Aussehen, das selbe.
Hallo!
Ich möchte eine Collection aus Rectangles an einen Container binden, der diese dann in einem gleichmäßigen Abstand anzeigt. Ein UniformGrid hat einen Abstand am Rand, den ich nicht möchte. Zusätzlich will ich auch in Zukunft die Breite des Containers dynamisch anpassen, je nachdem, ob ein Element am Rand aus der Collection verschwindet. Es soll die Darstellung der Gegner meines SpaceInvaders Klon sein.
Mein derzeitiger XAML Code
<StackPanel x:Name="stp_EnemyPanel" Orientation="Horizontal" Canvas.Top="50" Width="500" Height="30">
<ItemsControl ItemsSource="{Binding Enemies}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="1" Width="500"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</StackPanel>
Mein derzeitiges ViewModel
Opponent = new Enemy
{
Width = 30,
Height = 30,
Speed = 2,
HealthPoints = 3,
Color = new SolidColorBrush(Colors.DarkGreen)
};
//Collection fuer die Gegner und Hinzufuegen der Gegner
Enemies = new ObservableCollection<Rectangle>();
for (int i = 0; i < 10; i++)
{
Rectangle rectangle = new Rectangle
{
Width = Opponent.Width,
Height = Opponent.Height,
Fill = Opponent.Color
};
Enemies.Add(rectangle);
}
Zitat von Abt
Du arbeitest mit einer vergleichsweise komplexen Technologie. WPF ist nicht einsteigerfreundlich. Du wirst mit einem Try-and-Error Vorgehen echt nich weit kommen und immer wieder - wie hier - an Workarounds viel Zeit verlieren.
Wieso gehst Du nicht sturkturiert an die Sache?
Ich weiß ehrlich gesagt nicht wie ich da mit einer Struktur anfangen soll beziehungsweise wo ich anfangen soll.
Ich konnte das Problem auf eine Methode runterbrechen, aber ich weiß leider nicht was ich da ändern kann.
public GameScreen()
{
InitializeComponent();
this.DataContext = DataContext;
GameField.Focus();
Enemy();
}
private void Enemy()
{
enemyFigure = new Rectangle
{
Width = 50,
Height = 50,
Fill = new SolidColorBrush(Colors.DarkGreen),
Stroke = new SolidColorBrush(Colors.DarkGreen),
StrokeThickness = 5
};
Canvas.SetLeft(enemyFigure, 500);
Canvas.SetTop(enemyFigure, 50);
GameField.Children.Add(enemyFigure);
renderingEnemy = new EventHandler(OnRender);
CompositionTarget.Rendering -= renderingEnemy;
CompositionTarget.Rendering += renderingEnemy;
}
Hallo allerseits,
bei meinen ersten Spielereien mit Threading und Animationen, habe ich es hingekriegt jedes Event immer und immer wieder erneut aufzurufen. Wie setze ich die Events so, dass sie nur einmalig aufgerufen werden?
Das ist ein Beispiel, wie ich "versucht" habe das Problem zu lösen, aber die Leistung weiterhin nach einigen Sekunden stark eingebrochen ist.
public GameScreen()
{
GameField.KeyDown -= KeyIsDown;
GameField.KeyDown += KeyIsDown;
GameField.KeyUp -= KeyIsUp;
GameField.KeyUp += KeyIsUp;
renderPlayer = new EventHandler(Movement);
CompositionTarget.Rendering -= renderPlayer;
CompositionTarget.Rendering += renderPlayer;
}
Der Debugger hat mir gezeigt, dass die Logik vom Code-Behind verarbeitet wird und auch durchgegangen wird. Gezeigt wird mir davon, aber nix. Ich hab auch deinen Vorschlag ausprobiert und das Problem blieb das selbe. In einem seperaten Projekt hatte ich den gleichen xaml Code und die gleiche Logik dahinter und dort hat es funktioniert.
Hallo,
ich habe das Problem, dass wenn ich zu einer neuen Page navigiere, der Inhalt der Page nicht geladen wird beziehungsweise nur das xaml angezeigt wird, aber der code behind ignoriert wird.
Im ersten Block ist das Event für den Button, damit das Spiel gestartet wird (also die Page vom Spiel geöffnet wird). Der zweite Block ist das xaml der Page vom Spiel und der letzte Block ist das Code behind von der Page.
public partial class Menu : Page
{
public Menu()
{
InitializeComponent();
this.DataContext = DataContext;
}
/// <summary>
/// Click event für den Start Button
/// Startet das Spiel
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_start_Click(object sender, RoutedEventArgs e)
{
this.NavigationService.Navigate(new GameScreen());
}
<Page x:Class="SpaceInvaders.GameScreen"
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:SpaceInvaders"
mc:Ignorable="d"
MaxHeight="750" MaxWidth="550" MinHeight="750" MinWidth="550"
Title="GameScreen">
<Canvas Name="GameField" Height="750" Width="550" Margin="0,0,0,0" Background="Black" Focusable="True" KeyDown="GameTimeEvent">
<Polygon Name ="plgn_player" Fill="HotPink" Stroke="HotPink" StrokeThickness="1">
<Polygon.RenderTransform>
<TranslateTransform />
</Polygon.RenderTransform>
</Polygon>
</Canvas>
</Page>
public partial class GameScreen : Page
{
byte playerSpeed = 5;
public GameScreen()
{
InitializeComponent();
this.DataContext = DataContext;
plgn_player.RenderTransform = new TranslateTransform();
plgn_player.Points = new PointCollection
{
new Point(GameField.Width / 2 - 35,GameField.Height - 10),
new Point(GameField.Width / 2 - 35, GameField.Height - 10 - 15),
new Point(GameField.Width / 2 - 35+20,GameField.Height - 10 - 15),
new Point(GameField.Width / 2 - 35+20,GameField.Height - 10 - 22),
new Point(GameField.Width / 2 - 35+30,GameField.Height - 10 - 22),
new Point(GameField.Width / 2 - 35+30,GameField.Height - 10 - 15),
new Point(GameField.Width / 2 - 35+50,GameField.Height - 10 - 15),
new Point(GameField.Width / 2 - 35+50,GameField.Height - 10)
};
GameField.Focus();
GameField.KeyDown += GameTimeEvent;
}
private void GameTimeEvent(object sender, KeyEventArgs e)
{
TranslateTransform transform = (TranslateTransform)plgn_player.RenderTransform;
double widthToLeft = (GameField.Width / 2 - 35) * -1;
double widthToRight = Width - (GameField.Width / 2 - 35);
if (e.Key == Key.Left || e.Key == Key.A)
{
if (transform.X > widthToLeft)
{
transform.X -= playerSpeed;
}
}
if (e.Key == Key.Right || e.Key == Key.D)
{
if (transform.X < 280)
{
transform.X += playerSpeed;
}
}
}
}
Mit MVVM wollte ich mich erst später beschäftigen, weil ich mir dachte, dass mein Vorhaben ohne dem auch möglich wäre. Die Zeile mit dem Frame hab ich nicht mehr, weil ich das ziemlich schnell aufgegeben hatte.
Das ist soweit eben mein Versuch. Im xaml ist nur das Grid und ein Textblock
public partial class MainWindow : Window
{
public MainWindow()
{
this.DataContext = DataContext;
InitializeComponent();
Button start = new Button();
Button score = new Button();
Button exit = new Button();
start.Content = "START GAME";
start.Name = "btn_start";
start.Click += btn_start_Click;
start.Width = 200;
start.VerticalAlignment = VerticalAlignment.Center;
start.HorizontalAlignment = HorizontalAlignment.Center;
start.Background = Brushes.Blue;
start.Foreground = Brushes.White;
start.FontFamily = new FontFamily("Lucida Console");
start.FontSize = 20;
start.Padding = new Thickness(5, 5, 5, 5);
Grid.SetRow(start, 2);
score.Content = "SCOREBOARD";
score.Name = "btn_score";
score.Click += btn_score_Click;
score.Width = 200;
score.VerticalAlignment = VerticalAlignment.Center;
score.HorizontalAlignment = HorizontalAlignment.Center;
score.Background = Brushes.Blue;
score.Foreground = Brushes.White;
score.FontFamily = new FontFamily("Lucida Console");
score.FontSize = 20;
score.Padding = new Thickness(5, 5, 5, 5);
Grid.SetRow(score, 3);
exit.Content = "EXIT";
exit.Name = "btn_exit";
exit.Click += btn_exit_Click;
exit.Width = 200;
exit.VerticalAlignment = VerticalAlignment.Center;
exit.HorizontalAlignment = HorizontalAlignment.Center;
exit.Background = Brushes.Blue;
exit.Foreground = Brushes.White;
exit.FontFamily = new FontFamily("Lucida Console");
exit.FontSize = 20;
exit.Padding = new Thickness(5, 5, 5, 5);
Grid.SetRow(exit, 4);
MainMenuGrid.Children.Add(start);
MainMenuGrid.Children.Add(score);
MainMenuGrid.Children.Add(exit);
}
/// <summary>
/// Method to handle the buttonpress for the exit function
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_exit_Click(object sender, RoutedEventArgs e)
{
//Closes the application
Application.Current.Shutdown();
}
/// <summary>
/// Method to handle the buttonpress for the scoreboard
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_score_Click(object sender, RoutedEventArgs e)
{
//Change Context of the window/frame to the scoreboard page
//NavigationService.Navigate(new Scoreboard());
}
/// <summary>
/// Method to handle the buttonpress for the start of the game
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_start_Click(object sender, RoutedEventArgs e)
{
//Change context of the window/frame to the game page
}
}