Реализация программы Матричный дождь в WPF C#

343
19 января 2018, 21:50

На просторах интернета нашел реализацию Матричного дождя (падающие строки как в фильме Матрица). Реализация консольная и я решил попробовать перенести ее на WPF. В консоли символы дождя ставятся сразу в нужную позицию:

Console.SetCursorPosition(x, y);

Перед каждой вставкой может меняться цвет текста. Решил сделать через массив в который заносятся символы, а потом этот массив "печатается" в TextBox (реализация изменения цвета пока додумана, потом добавлю для каждого символа цвет и перейду на RichTextBox)

        tb.Clear();
        string s = "";
        for (int i = 0; i < mh; i++)
        {
            for (int j = 0; j < mw; j++)
            {
                s += MatrixArray[i, j];
            }
            s += "\n"; 
            tb.Text += s;
        }

В консоли было так:

public static void MatrixStep(int width, int height, int[] y, int[] l)
    {
        int x;
        thistime = !thistime;
        for (x = 0; x < width; ++x)
        {
            if (x % 11 == 10)
            {
                if (!thistime)
                    continue;
                Console.ForegroundColor = ConsoleColor.White;
            }
            else
            {
                Console.ForegroundColor = ConsoleColor.DarkGreen;
                Console.SetCursorPosition(x, inBoxY(y[x] - 2 - (l[x] / 40 * 2), height));
                Console.Write(R);
                Console.ForegroundColor = ConsoleColor.Green;
            }
            Console.SetCursorPosition(x, y[x]);
            Console.Write(R);
            y[x] = inBoxY(y[x] + 1, height);
            Console.SetCursorPosition(x, inBoxY(y[x] - l[x], height));
            Console.Write(' ');  // Основной фоновый символ в потоке
        }

Символы стразу выводились в консоль, а у меня сначала с массив. При выводе дождя наблюдается мерцание текста: Подскажите как можно оптимизировать данную задачу, или может есть более подходящий метод?

Воспользовался предложенным кодом с Canvas

        private void PrintMatrix(int x, int y, char r)
    {
        this.Dispatcher.Invoke((Action)(() =>
        {
            AddText(x, y, r);
            foreach (object myCanvasChild in cConsole.Children)
            {
                var tb = myCanvasChild as TextBlock;
                if (tb == null) return;
                var top = (double)tb.GetValue(Canvas.TopProperty);
                Canvas.SetTop(tb, top);
            }                                                                                    
        }));
    }
    private void AddText(int x, int y, char r)
    {
        Rectangle rct = new Rectangle();
        rct.Fill = Brushes.Black;
        rct.Height = 19;
        rct.Width = 17;
        Canvas.SetTop(rct, 21 * x + 4);
        Canvas.SetLeft(rct, 18 * y);
        cConsole.Children.Add(rct);
        var txt = new TextBlock
        {
            Text = r.ToString(),
            Foreground = tc,
            FontSize = 18,
            FontWeight = FontWeights.Bold,
            FontFamily = new FontFamily("Courier New")
        };
        Canvas.SetTop(txt, 21 * x + 5);
        Canvas.SetLeft(txt, 18 * y + 3);
        cConsole.Children.Add(txt);
    }

Но картинка на canvas подвисает:

Answer 1

code behind:

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace matrix
{
/// <summary>
///     Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
    {
    private readonly Random rnd = new Random();
    public MainWindow()
        {
        InitializeComponent();
        Task.Factory.StartNew(()=>
            {
            while (true)
            {
                Application.Current.Dispatcher.Invoke(()=>
                    {
                    AddText();
                    foreach (object myCanvasChild in MyCanvas.Children)
                    {
                        var tb = myCanvasChild as TextBlock;
                        if (tb == null) return;
                        var top = (double) tb.GetValue(Canvas.TopProperty);
                        Canvas.SetTop(tb, top + 50);
                    }
                    });
                Thread.Sleep(TimeSpan.FromMilliseconds(300));
            }
            });
        }
    private void AddText()
        {
        var txt = new TextBlock
        {
            Text = $"some message value ={rnd.Next()}",
            Foreground = new SolidColorBrush(Colors.Green)
        };
        Canvas.SetTop(txt, 0);
        MyCanvas.Children.Add(txt);
        }
    }
}

XAML

<Window x:Class="matrix.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"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">
<Canvas Name="MyCanvas">
</Canvas>

PS надо бы еще почистить ненужные элементы

READ ALSO
Вызов комбобокса через DataBindItems в ASP.NET

Вызов комбобокса через DataBindItems в ASP.NET

Есть два фрагмента кодаПервый, с комбобоксом:

264
Ошибка обобщения

Ошибка обобщения

Есть много сущностей, которые наследуются от класса BaseEntity<TKey>Операции, которые необходимо проводить над сущностями, абсолютно одинаковые,...

240
В чем разница между Type и TypeInfo?

В чем разница между Type и TypeInfo?

По моему, они имеют похожее назначение и очень похожи между собой

241
Функция, работающая только 10 раз в минуту c# [требует правки]

Функция, работающая только 10 раз в минуту c# [требует правки]

Функция вызывается, если в консоль пишешь test Если много раз писать это слово, то будет флуд, надо чтобы функцию можно было вызывать 10 раз в минуту

278