所以我正在用 C# 制作老虎機。我對 C# 真的很陌生,而且我真的很糟糕。到目前為止,我的專案進展順利。但是現在我想在單擊“旋轉”按鈕時隨機化顯示的影像。
我嘗試了很多不同的東西。我找到的解決方案要么是使用 PictureBox,要么是與我正在做的事情相去甚遠。
如果有人能看一下我的代碼并把我推向正確的方向,我將不勝感激。
提前致謝!
using System;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
namespace Prb.Slot.Machine.Wpf
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
int CoinInsert = 0;
private static Random random;
public enum SlotMachineIcon
{
Banana,
BigWin,
Cherry,
Lemon,
Orange,
Plum,
Seven,
Strawberry,
Watermelon
}
public MainWindow()
{
InitializeComponent();
}
private static void Init()
{
if (random == null) random = new Random();
}
public static int Random(int min, int max)
{
Init();
return random.Next(min, max);
}
void UpdateImage(Image wpfImage, SlotMachineIcon newIcon)
{
DirectoryInfo directoryInfo = new DirectoryInfo(Environment.CurrentDirectory);
directoryInfo = new DirectoryInfo(directoryInfo.Parent.Parent.Parent.Parent.FullName);
Uri uri = new Uri($"{directoryInfo.FullName}/images/{newIcon}.png");
wpfImage.Source = new BitmapImage(uri);
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
lblCoinsInserted.Content = 0;
lblCoinBalance.Content = 0;
lblCoinsWon.Content = 0;
UpdateImage(imgLeft, SlotMachineIcon.Cherry);
UpdateImage(imgMiddle, SlotMachineIcon.Banana);
UpdateImage(imgRight, SlotMachineIcon.Seven);
}
private void btnInsertCoins_Click(object sender, RoutedEventArgs e)
{
int.TryParse(txtInsertCoins.Text, out int InsertCoins);
if (InsertCoins > 0)
{
CoinInsert = int.Parse(txtInsertCoins.Text.ToString());
lblCoinBalance.Content = (int)lblCoinBalance.Content Convert.ToInt32(txtInsertCoins.Text);
lblCoinsInserted.Content = CoinInsert;
txtInsertCoins.Clear();
}
else
{
MessageBox.Show("Gelieve strikt positieve getallen in te vullen", "Ongeldig aantal munten", MessageBoxButton.OK, MessageBoxImage.Warning);
txtInsertCoins.Clear();
}
}
private void btnSpin_Click(object sender, RoutedEventArgs e)
{
int InsertedCoins = Convert.ToInt32(lblCoinsInserted.Content);
int CoinsBalance = Convert.ToInt32(lblCoinBalance.Content);
/*var v = Enum.GetValues(typeof(SlotMachineIcon));
int number = random.Next(10);*/
if (InsertedCoins == 0 | CoinsBalance == 0)
{
MessageBox.Show("Gelieve eerst munten in te werpen", "Geen munten ingeworpen", MessageBoxButton.OK, MessageBoxImage.Warning);
}
else
{
lblCoinBalance.Content = CoinsBalance - 1;
UpdateImage(imgLeft, SlotMachineIcon.Strawberry);
UpdateImage(imgMiddle, SlotMachineIcon.Watermelon);
UpdateImage(imgRight, SlotMachineIcon.Watermelon);
}
}
}
}
uj5u.com熱心網友回復:
編輯:正如@EmondErno 指出的那樣,移出了隨機宣告。
每次呼叫此方法時都會回傳一個隨機圖示:
private Random random = new();
private SlotMachineIcon GetRandomIcon()
{
return (SlotMachineIcon)random.Next(10); //don't forget to update this number if you add or remove icons
}
然后在每個 UpdateImage 方法中呼叫它,例如:
UpdateImage(imgLeft, GetRandomIcon());
UpdateImage(imgMiddle, GetRandomIcon());
UpdateImage(imgRight, GetRandomIcon());
uj5u.com熱心網友回復:
你試圖在后面的代碼中做所有事情,這是一個可怕的錯誤,原因有很多,其中你的程式在某些時候很難保持讀取和更新,并且你將程式的視圖和邏輯緊密耦合。您希望遵循 MVVM 模式并僅將代碼放在視圖邏輯后面(無資料)。
同樣在您的代碼中,您正在重新發明 WPF 中已經存在的更新系統,您想要使用資料系結和 WPF 更新系統并擺脫程式中的所有“更新圖示”邏輯。
這是您可以使用的 ViewModel (.net 5.0):
public class SlotViewModel: ISlotViewModel, INotifyPropertyChanged
{
private Random _r = new();
private int _slotChoicesCount;
private SlotSet _currentSlotSet;
private ICommand _spinCommand;
public SlotViewModel()
{
_slotChoicesCount = Enum.GetNames(typeof(SlotMachineIcon)).Length;
}
private SlotSet GetNewSet() => new(Enumerable.Range(0,3).Select(o => (SlotMachineIcon)_r.Next(_slotChoicesCount)).ToList());
public SlotSet CurrentSlotSet
{
get => _currentSlotSet;
set
{
if (Equals(value, _currentSlotSet)) return;
_currentSlotSet = value;
OnPropertyChanged();
}
}
public ICommand SpinCommand => _spinCommand ??= new DelegateCommand(s => { CurrentSlotSet = GetNewSet(); }, s => true);
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
最重要的部分是您的 ViewModel 實作了INotifyPropertyChanged. 當您使用 時SpinCommand,它會更新屬性CurrentSlotSet,這就是您需要擔心的全部。其余的都由 WPF 資料系結系統處理。
SlotSet 是一種呈現不可變結果的便捷方式:
public class SlotSet
{
public SlotMachineIcon Left { get; }
public SlotMachineIcon Middle { get; }
public SlotMachineIcon Right { get; }
public SlotSet(IList<SlotMachineIcon> triad)
{
Left = triad[0];
Middle = triad[1];
Right = triad[2];
}
public bool IsWinner => Left == Middle && Middle == Right; // just an example
}
ISlotViewModel 是你的 ViewModel 滿足的介面(契約)。
public interface ISlotViewModel
{
ICommand SpinCommand { get; }
SlotSet CurrentSlotSet { get; set; }
}
輔助類 DelegateCommand:
public class DelegateCommand : ICommand
{
private readonly Predicate<object> _canExecute;
private readonly Action<object> _execute;
public event EventHandler CanExecuteChanged;
public DelegateCommand(Action<object> execute, Predicate<object> canExecute = null)
{
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter) => _canExecute == null || _canExecute(parameter);
public void Execute(object parameter) => _execute(parameter);
public void RaiseCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
在您的視圖中,XAML 部分,您只需要像這樣簡單的東西:
<Button Command="{Binding SpinCommand}">spin</Button>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding CurrentSlotSet.Left}"/>
<Image Source="{Binding CurrentSlotSet.Middle}"/>
<Image Source="{Binding CurrentSlotSet.Right}"/>
</StackPanel>
在 Windows 標記中有這樣的:
xmlns:local="clr-namespace:SlotMachine"
d:DataContext="{d:DesignInstance Type=local:SlotViewModel, IsDesignTimeCreatable=True}"
后面的代碼就這么簡單:
public ISlotViewModel ViewModel
{
get { return (ISlotViewModel)DataContext; }
set { DataContext = value; }
}
public SlotView() // or MainWindow
{
InitializeComponent();
ViewModel = new SlotViewModel();
}
這里唯一缺少的是在每個 . 中添加一個轉換器<Image,它將一個SlotMachineIcon值轉換為影像路徑。
PS:如果你沒有 resharper,你可能也需要這個類:
[AttributeUsage(AttributeTargets.Method)]
public sealed class NotifyPropertyChangedInvocatorAttribute : Attribute
{
public NotifyPropertyChangedInvocatorAttribute() { }
public NotifyPropertyChangedInvocatorAttribute([NotNull] string parameterName)
{
ParameterName = parameterName;
}
[CanBeNull] public string ParameterName { get; }
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/342843.html
下一篇:用于登錄WpfC#的彩色文本
