Windows Phone 8: Создаем приложение. Матрица. Часть 2

    Windows Phone 8: Создаем приложение. Матрица. Часть 1
    Windows Phone 8: Создаем приложение. Матрица. Часть 2

    Здравствуйте. Сегодня мы продолжим создание приложения, используем новый шаблон «Панорама», а так же добавим всевозможные настройки, что позволит изменять все параметры матрицы. Сразу оговорюсь, что при задании сильно больших чисел в некоторых настройках, резко понижается производительность, но с этим мы еще будем бороться в следующих частях.

    Так же хочу сразу вспомнить основные цели этих статей: это написание приложения с использованием максимального числа всего: различных контролов, техник, шаблонов и т.д. Ну а так же получение конечного продукта с заданными свойствами.


    Скриншот работы приложения

    Хотелось вторую часть написать полностью отточенную, в плане кода, однако размеры ее стали достаточно большими. Если сразу провести еще и оптимизацию, то это усложнит прослеживание логики. Оптимизация будет в следующей части. Начнем.

    Цели этой части


    1. Использовать шаблон Панорама
    2. Создание настроек приложения

    Добавлены следующие настройки


    • Скорость смены символов в заданном диапазоне
    • Количество змеек в очереди
    • Количество одновременно ползущих змеек за нажатие
    • Размер шрифта
    • Старт / Стоп
    • Очистка экрана
    • Размер(количество) клеточек в матрице
    • Длина змейки в заданном диапазоне
    • Горизонтальная / Вертикальная ориентация
    • Выбор языка падающих символов
    • Цвет фона матрицы
    • Цвет первого символа
    • Градиент для змейки

    Можно посмотреть эти настройки на видео:




    Перейдем к работе в Visual Studio


    Создаем новый проект. Приложение Windows Phone с панорамой.
    У меня имя будет SE_Matrix_2d_v_4.
    Остальное как в прошлый раз.

    MainPage.xaml


    Тут у нас добавилось немного кода. В шаблоне Панорама у меня 3 секции:

    <!--Элемент управления Panorama-->
            <phone:Panorama Title="">
                <phone:Panorama.Background>
                    <ImageBrush />
                </phone:Panorama.Background>
    
                <!--Первый элемент Panorama-->
                <phone:PanoramaItem >
    ...
                </phone:PanoramaItem>
    
                <!--Второй элемент Panorama-->
                <phone:PanoramaItem>   
    ...
                </phone:PanoramaItem>
    
                <!--Третий элемент Panorama-->
                <phone:PanoramaItem>   
    ...
                </phone:PanoramaItem>
            </phone:Panorama>
    

    В первый элемент добавим непосредственно отображение матрицы. Тут ничего не поменялось, все как и в первой части:

                <!--Первый элемент Panorama-->
                <phone:PanoramaItem >
                    <Grid x:Name="LayoutRootSecond" Background="Black" Margin="0,-32,-2,7" RenderTransformOrigin="0.500,0.500" Tap="Event_Grid_Tap_LayoutRoot"/>
                </phone:PanoramaItem>
    

    Во второй элемент управления добавлены первые 9 настроек из 13, описанных в начале статьи. Ничего сложного: название в TextBlock, TextBox для ввода значений и Button для применения заданного значения. Так же все обернуто в ScrollViewer для возможности вертикальной прокрутки, так как список в один экран не влезает. В большинстве TextBox метод ввода выбран как числа, InputScope=«Number». Однако в паре элементов есть возможность вводить отрицательные значения. Временно используется общая клавиатура InputScope=«Default».

    Код. Второй элемент Panorama
                <!--Второй элемент Panorama-->
                <phone:PanoramaItem>    
                    <Grid x:Name="LayoutRootThierd" Grid.Column="1" Background="Transparent" Margin="0, 0,-2,7" RenderTransformOrigin="0.500,0.500" >
                        <ScrollViewer  HorizontalScrollBarVisibility="Auto"  >
                            <Grid x:Name="Grid_SettingsRight" Grid.Column="1" Background="Transparent" Margin="0, 0,-2,7" RenderTransformOrigin="0.500,0.500" >
                                <!-- Скорость падения змейки в мс/ Скорость смены символов в мс -->
                                <TextBlock HorizontalAlignment="Left" Margin="28,3,0,0" TextWrapping="Wrap" Text="Скорость смены символов в мс" VerticalAlignment="Top" Width="352"/>
                                <TextBox x:Name="TextBox_SppeedFrom" InputScope="Number" HorizontalAlignment="Left" Height="67" TextWrapping="Wrap" Text="20" VerticalAlignment="Top" Width="100" Margin="9,28,0,0"/>
                                <TextBox x:Name="TextBox_SppeedTo" InputScope="Number" HorizontalAlignment="Left" Height="67" TextWrapping="Wrap" Text="40" VerticalAlignment="Top" Width="100" Margin="114,28,0,0"/>
                                <Button x:Name="Button_SpeedApplay" Content=" Ok " HorizontalAlignment="Left" Height="65" Margin="288,30,0,0" VerticalAlignment="Top" Click="Event_Button_Click_SpeedApplay"/>
    
                                <!-- Количество змеек в очереди -->
                                <TextBlock HorizontalAlignment="Left" Margin="28,95,0,0" TextWrapping="Wrap" Text="Количество змеек в очереди" VerticalAlignment="Top" RenderTransformOrigin="-0.256,0.233" Width="352"/>
                                <TextBox x:Name="TextBox_CountQueue" InputScope="Number" HorizontalAlignment="Left" Height="67" Margin="10,127,0,0" TextWrapping="Wrap" Text="5" VerticalAlignment="Top" Width="101" RenderTransformOrigin="0.49,-0.049"/>
                                <Button x:Name="Button_CountQueue" Content=" Ok " HorizontalAlignment="Left" Margin="287,127,0,0" VerticalAlignment="Top" Click="Event_Button_Click_CountQueue" RenderTransformOrigin="1.474,0.483" Height="67"/>
    
                                <!-- Количество змеек за нажатие -->
                                <TextBlock HorizontalAlignment="Left" Margin="28,194,0,0" TextWrapping="Wrap" Text="Количество змеек за нажатие" VerticalAlignment="Top" Width="352"/>
                                <TextBox x:Name="TextBox_СountSimultaneously" InputScope="Number" HorizontalAlignment="Left" Height="72" Margin="10,221,0,0" TextWrapping="Wrap" Text="1" VerticalAlignment="Top" Width="101"/>
                                <Button x:Name="Button_СountSimultaneously" Content=" Ok " HorizontalAlignment="Left" Margin="288,221,0,0" VerticalAlignment="Top" Click="Event_Button_Click_СountSimultaneously" RenderTransformOrigin="1.474,0.483"/>
    
                                <!-- Размер шрифта -->
                                <TextBlock HorizontalAlignment="Left" Margin="27,293,0,0" TextWrapping="Wrap" Text="Размер шрифта (+ - [n])" VerticalAlignment="Top" Width="352"/>
                                <TextBox x:Name="TextBox_FontSize" InputScope="Default" HorizontalAlignment="Left" Height="72" Margin="9,320,0,0" TextWrapping="Wrap" Text="-2" VerticalAlignment="Top" Width="101"/>
                                <Button x:Name="Button_FontSize" Content=" Ok " HorizontalAlignment="Left" Margin="288,320,0,0" VerticalAlignment="Top" Click="Event_Button_Click_FontSize" RenderTransformOrigin="1.474,0.483"/>
    
                                <!-- Количество смены символов в ячейке -->
                                <TextBlock HorizontalAlignment="Left" Margin="28,392,0,0" TextWrapping="Wrap" Text="Количество смены символов" VerticalAlignment="Top" Width="352"/>
                                <TextBox x:Name="TextBox_CountSymbol" InputScope="Number" HorizontalAlignment="Left" Height="72" Margin="10,419,0,0" TextWrapping="Wrap" Text="3" VerticalAlignment="Top" Width="101"/>
                                <Button x:Name="Button_CountSymbol" Content=" Ok " HorizontalAlignment="Left" Margin="288,419,0,0" VerticalAlignment="Top" Click="Event_Button_Click_CountSymbol" RenderTransformOrigin="1.474,0.483"/>
    
                                <!-- Сатрт / Стоп анимация -->
                                <TextBlock x:Name="TextBlock_OnOff" HorizontalAlignment="Left" Margin="28,491,0,0" TextWrapping="Wrap" Text="Вкл/Выкл анимацию" VerticalAlignment="Top" Width="352"/>
                                <ToggleButton x:Name="Button_Stop" Content="Stop" HorizontalAlignment="Left" Margin="214,523,0,0" VerticalAlignment="Top" Click="Event_Button_Click_Stop" Width="180"/>
                                <ToggleButton x:Name="Button_Start" Content="Start" HorizontalAlignment="Left" Margin="10,523,0,0" VerticalAlignment="Top" Click="Event_Button_Click_Start" Width="180"/>
                                
                                <!-- Очистка экрана -->
                                <TextBlock HorizontalAlignment="Left" Margin="28,605,0,0" TextWrapping="Wrap" Text="Хотите очистит экран?" VerticalAlignment="Top" Width="352"/>
                                <Button Content=" YES " HorizontalAlignment="Left" Margin="10,632,0,0" VerticalAlignment="Top" Width="371" Click="Event_Button_Click_Clear"/>
    
                                <!-- Размер клетки для символа -->
                                <TextBlock HorizontalAlignment="Left" Margin="27,709,0,0" TextWrapping="Wrap" Text="Размер клетки для символа" VerticalAlignment="Top" Width="369"/>
                                <TextBox x:Name="TextBox_ElementSize" InputScope="Default" HorizontalAlignment="Left" Height="72" Margin="10,734,0,-17" TextWrapping="Wrap" Text="-6" VerticalAlignment="Top" Width="101"/>
                                <Button Content="Ok" HorizontalAlignment="Left" Margin="286,736,0,-19" VerticalAlignment="Top" Width="93" Click="Event_Button_Click_ElementSize"/>
    
                                <!-- Длина змейки -->
                                <TextBlock HorizontalAlignment="Left" Margin="27,809,0,0" TextWrapping="Wrap" Text="Длина змейки от: до:" VerticalAlignment="Top" Width="369"/>
                                <TextBox x:Name="TextBox_MinLength" InputScope="Number" HorizontalAlignment="Left" Height="72" Margin="10,834,0,-17" TextWrapping="Wrap" Text="3" VerticalAlignment="Top" Width="101"/>
                                <TextBox x:Name="TextBox_MaxLength" InputScope="Number" HorizontalAlignment="Left" Height="67" TextWrapping="Wrap" Text="10" VerticalAlignment="Top" Width="100" Margin="114,834,0,-17"/>
                                <Button Content="Ok" HorizontalAlignment="Left" Margin="286,836,0,-19" VerticalAlignment="Top" Width="93" Click="Event_Button_Click_MaxLength"/>
                                
                                <!-- Горизонтакльное /  вертикальное расположение -->
                                <TextBlock HorizontalAlignment="Left" Margin="28,905,0,0" TextWrapping="Wrap" Text="Повернуть матрицу" VerticalAlignment="Top" Width="352"/>
                                <ToggleButton x:Name="ToggleButton_Turn" Content="Вертикально" HorizontalAlignment="Left" Margin="10,932,0,0" VerticalAlignment="Top" Width="371" Click="Event_Button_Click_Turn"/>                        
                            </Grid>
                        </ScrollViewer>
                    </Grid>
    


    В третьем элементе остались последние 4 настройки: выбор языка, цвета и задание цвета первому элементу, фону, градиента для змейки. Так же все находится в ScrollViewer для вертикальной прокрутки. Однако тут пришлось использовать один нестандартный элемент управления, а именно ColorPicker. Его можно найти в дополнительной библиотеке элементов с названием Coding4Fun.

    Как установить Coding4Fun

    У меня последние пару недель с нугет проблемы, поэтому качал вручную.
    Переходим по ссылке.
    Нажимаем на большую красную кнопку с надписью «Via CodePlex Current Release Zip».
    Качаем архив с именем «Coding4Fun.Toolkit (Windows Phone 8).zip».
    Из архива копируем файл с именем «Coding4Fun.Toolkit.Controls.dll» к себе в проект.
    Заходим в проект в папочку «References». Жмем на нее правой кнопкой — Добавить ссылку — Справа внизу выбираем Обзор… Находим нашу библиотеку и жмем ОК.
    Заходим в Панель элементов. правой кнопкой где угодно в ее приделах — Выбрать элементы… Выбираем вкладку Windows Phone Components. Справа внизу жмем обзор и снова выбираем Coding4Fun.Toolkit.Controls.dll. Новые элементы будут подсвечены. Смотрим, что б возле элемента ColorPicker была галочка.
    Убедитесь, что в начале файла добавилась строчка

        xmlns:Controls="clr-namespace:Coding4Fun.Toolkit.Controls;assembly=Coding4Fun.Toolkit.Controls"
    

    Продолжим. Перетаскиваем ColorPicker с Панели элементов. Назначаем имя. Теперь выбирать цвет будем на одном элементе, а применять выбранный цвет разными кнопками к разным характеристикам матрицы.

                                <!-- Элемент выбора цвета. Codding4Fun -->
                                <Controls:ColorPicker x:Name="ColorPicker" VerticalAlignment="Top" Height="360" Margin="10,154,10,0"/>
                                <TextBlock HorizontalAlignment="Left" Margin="10,114,0,0" TextWrapping="Wrap" Text="Выбирете цвет" VerticalAlignment="Top" Width="412" Height="35"/>
    

    Так же добавим кнопку, при нажатии на которую будет появляться всплывающее окно для выбора языка:

                                <!-- Выбор языка символов -->
                                <StackPanel Margin="0,0,0,649" >
                                    <!-- Всплывающее окно -->
                                    <Popup  Name="Popup_ButtonDropDownSelectLanguage" Margin="0,0,10,0">
                                        <StackPanel Margin="10,50,0,0" Background="DarkGray"  Width="393" Name="StackPanel_ButtonDropDownSelectLanguage">
                                        </StackPanel>
                                    </Popup>
                                    <TextBlock TextWrapping="Wrap" Text="Выбирете язык символов"/>
                                    <!-- Кнопка, отображающая выбранный язык. При нажатии на нее всплывает окно -->
                                    <Button Margin="0,10,10,0" x:Name="Button_SelectLanguage" Content="Китайский"  Click="Event_Button_Click_SelectLanguage" Height="74" />
                                </StackPanel>
    

    И еще пара кнопок по аналогии со вторым элементом панорамы.

    Код. Третий элемент Panorama
                <!--Третий элемент Panorama-->
                <phone:PanoramaItem >
                    <Grid x:Name="LayoutRoot123" Background="Transparent" Margin="0,-32,-2,7" RenderTransformOrigin="0.500,0.500" >
                        <ScrollViewer HorizontalScrollBarVisibility="Hidden" Margin="0,26,0,0" >                     
                            <Grid Margin="0,0,0,0" Height="984" >
                                <!-- Выбор языка символов -->
                                <StackPanel Margin="0,0,0,649" >
                                    <!-- Всплывающее окно -->
                                    <Popup  Name="Popup_ButtonDropDownSelectLanguage" Margin="0,0,10,0">
                                        <StackPanel Margin="10,50,0,0" Background="DarkGray"  Width="393" Name="StackPanel_ButtonDropDownSelectLanguage">
                                        </StackPanel>
                                    </Popup>
                                    <TextBlock TextWrapping="Wrap" Text="Выбирете язык символов"/>
                                    <!-- Кнопка, отображающая выбранный язык. При нажатии на нее всплывает окно -->
                                    <Button Margin="0,10,10,0" x:Name="Button_SelectLanguage" Content="Китайский"  Click="Event_Button_Click_SelectLanguage" Height="74" />
                                </StackPanel>
                                
                                <!-- Элемент выбора цвета. Codding4Fun -->
                                <Controls:ColorPicker x:Name="ColorPicker" VerticalAlignment="Top" Height="360" Margin="10,154,10,0"/>
                                <TextBlock HorizontalAlignment="Left" Margin="10,114,0,0" TextWrapping="Wrap" Text="Выбирете цвет" VerticalAlignment="Top" Width="412" Height="35"/>
                               
                                <!-- Выбор фона матрицы -->
                                <Button x:Name="Button_BackgroundColor" Content="Цвет фона" HorizontalAlignment="Left" Margin="10,533,0,0" VerticalAlignment="Top" RenderTransformOrigin="-0.404,-0.757" Width="412" Click="Event_Button_Click_ChangeBackground"/>
                                
                                <!-- Выбор цвета первого символа -->
                                <Button x:Name="Button_FirstSymbolColor" Content="Цвет первого символа" HorizontalAlignment="Left" Margin="10,605,0,0" VerticalAlignment="Top" Width="412" Click="Event_Button_Click_FirstSymbolColor"/>
                                
                                <!-- Выбор цвета градиента змейки -->
                                <TextBlock HorizontalAlignment="Left" Margin="10,682,0,0" TextWrapping="Wrap" Text="Выберите цвета градиента змейки" VerticalAlignment="Top" RenderTransformOrigin="-0.915,-1.222" Width="412"/>
                                <Button x:Name="Button_GradientFrom" Content="От" HorizontalAlignment="Left" Margin="10,714,0,0" VerticalAlignment="Top" Width="180" Click="Event_Button_Click_GradientFrom"/>
                                <Button x:Name="Button_GradientTo" Content="До" HorizontalAlignment="Left" Margin="245,714,0,0" VerticalAlignment="Top" Width="180" Click="Event_Button_Click_GradientTo"/>
                            </Grid>
                        </ScrollViewer>
                    </Grid>
                </phone:PanoramaItem>
    


    Код. MainPage.xaml
    <phone:PhoneApplicationPage
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
        xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:UI="clr-namespace:Microsoft.Advertising.Mobile.UI;assembly=Microsoft.Advertising.Mobile.UI"
        xmlns:Controls="clr-namespace:Coding4Fun.Toolkit.Controls;assembly=Coding4Fun.Toolkit.Controls"
        x:Class="SE_Matrix_2d_v_4.MainPage"
        mc:Ignorable="d"
        d:DataContext="{d:DesignData SampleData/MainViewModelSampleData.xaml}"
        FontFamily="{StaticResource PhoneFontFamilyNormal}"
        FontSize="{StaticResource PhoneFontSizeNormal}"
        Foreground="{StaticResource PhoneForegroundBrush}"
        SupportedOrientations="Portrait"  Orientation="Portrait"
        shell:SystemTray.IsVisible="False">
    
        <!--LayoutRoot представляет корневую сетку, где размещается все содержимое страницы-->
        <Grid x:Name="LayoutRoot" Background="Transparent">
    
            <!-- ПРИМЕЧАНИЕ О ЛОКАЛИЗАЦИИ:
                Чтобы локализовать отображаемые строки, скопируйте их значения в соответствующим образом названные
                ключи в файле ресурсов нейтрального языка приложения (AppResources.resx), а затем
                замените жестко заданное текстовое значение между кавычками атрибутов
                на выражение привязки, указывающее на имя соответствующей строки.
    
                Пример:
    
                    Text="{Binding Path=LocalizedResources.ApplicationTitle, Source={StaticResource LocalizedStrings}}"
    
                Данная привязка указывает на строковый ресурс шаблона с именем "ApplicationTitle".
    
                Добавление поддерживаемых языков на вкладку "Свойства проекта" создает
                новый RESX-файл для каждого языка, в котором могут храниться переведенные значения
                строк пользовательского интерфейса. Привязка в этих примерах вызывает отрисовку
                значений атрибутов из RESX-файла, соответствующего
                CurrentUICulture приложения во время выполнения.
             -->
    
            <!--Элемент управления Panorama-->
            <phone:Panorama Title="">
                <phone:Panorama.Background>
                    <ImageBrush />
                </phone:Panorama.Background>
    
                <!--Первый элемент Panorama-->
                <phone:PanoramaItem >
                    <!--Тут создается и отображается матрица-->
                    <Grid x:Name="LayoutRootSecond" Background="Black" Margin="0,-32,-2,7" RenderTransformOrigin="0.500,0.500" Tap="Event_Grid_Tap_LayoutRoot"/>
                </phone:PanoramaItem>
    
                <!--Второй элемент Panorama-->
                <phone:PanoramaItem>    
                    <Grid x:Name="LayoutRootThierd" Grid.Column="1" Background="Transparent" Margin="0, 0,-2,7" RenderTransformOrigin="0.500,0.500" >
                        <ScrollViewer  HorizontalScrollBarVisibility="Auto"  >
                            <Grid x:Name="Grid_SettingsRight" Grid.Column="1" Background="Transparent" Margin="0, 0,-2,7" RenderTransformOrigin="0.500,0.500" >
                                <!-- Скорость падения змейки в мс/ Скорость смены символов в мс -->
                                <TextBlock HorizontalAlignment="Left" Margin="28,3,0,0" TextWrapping="Wrap" Text="Скорость смены символов в мс" VerticalAlignment="Top" Width="352"/>
                                <TextBox x:Name="TextBox_SppeedFrom" InputScope="Number" HorizontalAlignment="Left" Height="67" TextWrapping="Wrap" Text="20" VerticalAlignment="Top" Width="100" Margin="9,28,0,0"/>
                                <TextBox x:Name="TextBox_SppeedTo" InputScope="Number" HorizontalAlignment="Left" Height="67" TextWrapping="Wrap" Text="40" VerticalAlignment="Top" Width="100" Margin="114,28,0,0"/>
                                <Button x:Name="Button_SpeedApplay" Content=" Ok " HorizontalAlignment="Left" Height="65" Margin="288,30,0,0" VerticalAlignment="Top" Click="Event_Button_Click_SpeedApplay"/>
    
                                <!-- Количество змеек в очереди -->
                                <TextBlock HorizontalAlignment="Left" Margin="28,95,0,0" TextWrapping="Wrap" Text="Количество змеек в очереди" VerticalAlignment="Top" RenderTransformOrigin="-0.256,0.233" Width="352"/>
                                <TextBox x:Name="TextBox_CountQueue" InputScope="Number" HorizontalAlignment="Left" Height="67" Margin="10,127,0,0" TextWrapping="Wrap" Text="5" VerticalAlignment="Top" Width="101" RenderTransformOrigin="0.49,-0.049"/>
                                <Button x:Name="Button_CountQueue" Content=" Ok " HorizontalAlignment="Left" Margin="287,127,0,0" VerticalAlignment="Top" Click="Event_Button_Click_CountQueue" RenderTransformOrigin="1.474,0.483" Height="67"/>
    
                                <!-- Количество змеек за нажатие -->
                                <TextBlock HorizontalAlignment="Left" Margin="28,194,0,0" TextWrapping="Wrap" Text="Количество змеек за нажатие" VerticalAlignment="Top" Width="352"/>
                                <TextBox x:Name="TextBox_СountSimultaneously" InputScope="Number" HorizontalAlignment="Left" Height="72" Margin="10,221,0,0" TextWrapping="Wrap" Text="1" VerticalAlignment="Top" Width="101"/>
                                <Button x:Name="Button_СountSimultaneously" Content=" Ok " HorizontalAlignment="Left" Margin="288,221,0,0" VerticalAlignment="Top" Click="Event_Button_Click_СountSimultaneously" RenderTransformOrigin="1.474,0.483"/>
    
                                <!-- Размер шрифта -->
                                <TextBlock HorizontalAlignment="Left" Margin="27,293,0,0" TextWrapping="Wrap" Text="Размер шрифта (+ - [n])" VerticalAlignment="Top" Width="352"/>
                                <TextBox x:Name="TextBox_FontSize" InputScope="Default" HorizontalAlignment="Left" Height="72" Margin="9,320,0,0" TextWrapping="Wrap" Text="-2" VerticalAlignment="Top" Width="101"/>
                                <Button x:Name="Button_FontSize" Content=" Ok " HorizontalAlignment="Left" Margin="288,320,0,0" VerticalAlignment="Top" Click="Event_Button_Click_FontSize" RenderTransformOrigin="1.474,0.483"/>
    
                                <!-- Количество смены символов в ячейке -->
                                <TextBlock HorizontalAlignment="Left" Margin="28,392,0,0" TextWrapping="Wrap" Text="Количество смены символов" VerticalAlignment="Top" Width="352"/>
                                <TextBox x:Name="TextBox_CountSymbol" InputScope="Number" HorizontalAlignment="Left" Height="72" Margin="10,419,0,0" TextWrapping="Wrap" Text="3" VerticalAlignment="Top" Width="101"/>
                                <Button x:Name="Button_CountSymbol" Content=" Ok " HorizontalAlignment="Left" Margin="288,419,0,0" VerticalAlignment="Top" Click="Event_Button_Click_CountSymbol" RenderTransformOrigin="1.474,0.483"/>
    
                                <!-- Сатрт / Стоп анимация -->
                                <TextBlock x:Name="TextBlock_OnOff" HorizontalAlignment="Left" Margin="28,491,0,0" TextWrapping="Wrap" Text="Вкл/Выкл анимацию" VerticalAlignment="Top" Width="352"/>
                                <ToggleButton x:Name="Button_Stop" Content="Stop" HorizontalAlignment="Left" Margin="214,523,0,0" VerticalAlignment="Top" Click="Event_Button_Click_Stop" Width="180"/>
                                <ToggleButton x:Name="Button_Start" Content="Start" HorizontalAlignment="Left" Margin="10,523,0,0" VerticalAlignment="Top" Click="Event_Button_Click_Start" Width="180"/>
                                
                                <!-- Очистка экрана -->
                                <TextBlock HorizontalAlignment="Left" Margin="28,605,0,0" TextWrapping="Wrap" Text="Хотите очистит экран?" VerticalAlignment="Top" Width="352"/>
                                <Button Content=" YES " HorizontalAlignment="Left" Margin="10,632,0,0" VerticalAlignment="Top" Width="371" Click="Event_Button_Click_Clear"/>
    
                                <!-- Размер клетки для символа -->
                                <TextBlock HorizontalAlignment="Left" Margin="27,709,0,0" TextWrapping="Wrap" Text="Размер клетки для символа" VerticalAlignment="Top" Width="369"/>
                                <TextBox x:Name="TextBox_ElementSize" InputScope="Default" HorizontalAlignment="Left" Height="72" Margin="10,734,0,-17" TextWrapping="Wrap" Text="-6" VerticalAlignment="Top" Width="101"/>
                                <Button Content="Ok" HorizontalAlignment="Left" Margin="286,736,0,-19" VerticalAlignment="Top" Width="93" Click="Event_Button_Click_ElementSize"/>
    
                                <!-- Длина змейки -->
                                <TextBlock HorizontalAlignment="Left" Margin="27,809,0,0" TextWrapping="Wrap" Text="Длина змейки от: до:" VerticalAlignment="Top" Width="369"/>
                                <TextBox x:Name="TextBox_MinLength" InputScope="Number" HorizontalAlignment="Left" Height="72" Margin="10,834,0,-17" TextWrapping="Wrap" Text="3" VerticalAlignment="Top" Width="101"/>
                                <TextBox x:Name="TextBox_MaxLength" InputScope="Number" HorizontalAlignment="Left" Height="67" TextWrapping="Wrap" Text="10" VerticalAlignment="Top" Width="100" Margin="114,834,0,-17"/>
                                <Button Content="Ok" HorizontalAlignment="Left" Margin="286,836,0,-19" VerticalAlignment="Top" Width="93" Click="Event_Button_Click_MaxLength"/>
                                
                                <!-- Горизонтакльное /  вертикальное расположение -->
                                <TextBlock HorizontalAlignment="Left" Margin="28,905,0,0" TextWrapping="Wrap" Text="Повернуть матрицу" VerticalAlignment="Top" Width="352"/>
                                <ToggleButton x:Name="ToggleButton_Turn" Content="Вертикально" HorizontalAlignment="Left" Margin="10,932,0,0" VerticalAlignment="Top" Width="371" Click="Event_Button_Click_Turn"/>                        
                            </Grid>
                        </ScrollViewer>
                    </Grid>
                        
                </phone:PanoramaItem>
    
                <!--Третий элемент Panorama-->
                <phone:PanoramaItem >
                    <Grid x:Name="LayoutRoot123" Background="Transparent" Margin="0,-32,-2,7" RenderTransformOrigin="0.500,0.500" >
                        <ScrollViewer HorizontalScrollBarVisibility="Hidden" Margin="0,26,0,0" >                     
                            <Grid Margin="0,0,0,0" Height="984" >
                                <!-- Выбор языка символов -->
                                <StackPanel Margin="0,0,0,649" >
                                    <!-- Всплывающее окно -->
                                    <Popup  Name="Popup_ButtonDropDownSelectLanguage" Margin="0,0,10,0">
                                        <StackPanel Margin="10,50,0,0" Background="DarkGray"  Width="393" Name="StackPanel_ButtonDropDownSelectLanguage">
                                        </StackPanel>
                                    </Popup>
                                    <TextBlock TextWrapping="Wrap" Text="Выбирете язык символов"/>
                                    <!-- Кнопка, отображающая выбранный язык. При нажатии на нее всплывает окно -->
                                    <Button Margin="0,10,10,0" x:Name="Button_SelectLanguage" Content="Китайский"  Click="Event_Button_Click_SelectLanguage" Height="74" />
                                </StackPanel>
                                
                                <!-- Элемент выбора цвета. Codding4Fun -->
                                <Controls:ColorPicker x:Name="ColorPicker" VerticalAlignment="Top" Height="360" Margin="10,154,10,0"/>
                                <TextBlock HorizontalAlignment="Left" Margin="10,114,0,0" TextWrapping="Wrap" Text="Выбирете цвет" VerticalAlignment="Top" Width="412" Height="35"/>
                               
                                <!-- Выбор фона матрицы -->
                                <Button x:Name="Button_BackgroundColor" Content="Цвет фона" HorizontalAlignment="Left" Margin="10,533,0,0" VerticalAlignment="Top" RenderTransformOrigin="-0.404,-0.757" Width="412" Click="Event_Button_Click_ChangeBackground"/>
                                
                                <!-- Выбор цвета первого символа -->
                                <Button x:Name="Button_FirstSymbolColor" Content="Цвет первого символа" HorizontalAlignment="Left" Margin="10,605,0,0" VerticalAlignment="Top" Width="412" Click="Event_Button_Click_FirstSymbolColor"/>
                                
                                <!-- Выбор цвета градиента змейки -->
                                <TextBlock HorizontalAlignment="Left" Margin="10,682,0,0" TextWrapping="Wrap" Text="Выберите цвета градиента змейки" VerticalAlignment="Top" RenderTransformOrigin="-0.915,-1.222" Width="412"/>
                                <Button x:Name="Button_GradientFrom" Content="От" HorizontalAlignment="Left" Margin="10,714,0,0" VerticalAlignment="Top" Width="180" Click="Event_Button_Click_GradientFrom"/>
                                <Button x:Name="Button_GradientTo" Content="До" HorizontalAlignment="Left" Margin="245,714,0,0" VerticalAlignment="Top" Width="180" Click="Event_Button_Click_GradientTo"/>
                            </Grid>
                        </ScrollViewer>
                    </Grid>
                </phone:PanoramaItem>
            </phone:Panorama>
    
            <!--Раскомментируйте, чтобы увидеть сетку выравнивания и выровнять
                элементы управления по общим границам.  Верхнее поле изображения равно -32 пикселя, чтобы
                осталось место для области уведомлений. Установите его равным 0 (или вообще удалите поле),
                если область уведомлений скрыта.
    
                Перед сдачей приложения удалите этот код XAML и само изображение.-->
            <!--<Image Source="/Assets/AlignmentGrid.png" VerticalAlignment="Top" Height="800" Width="480" Margin="0" Grid.Row="0" Grid.RowSpan="2" IsHitTestVisible="False" />-->
    
        </Grid>
    </phone:PhoneApplicationPage>
    


    Внешне настройки выглядят так:





    MainPage.xaml.cs


    Первым делом создаем свойства класса, которые будут отвечать за настройки:
    Код. Свойства класса
            /* ****************************** Свойства класса ****************************** */
            // Случайное число
            Random random = new Random();
    
            // Количество змеек после нажатия на экран в очереди
            int iteration = 5;
    
            // Количество одновременно появляющихся змеек после нажатия
            int countSimultaneously = 3;
    
            // Скорость смены символов
            int speedFrom = 20;
            int speedTo = 40;
    
            // Размер клетки для символа
            int addingSize = -6;
    
            // Итоговый размер шрифта
            int fontSize;
    
            // Минимальная и максимальная длина змейки
            int minLength = 10;
            int maxLength = 15;
    
            // Получаем расширение экрана
            double ScreenWidth = System.Windows.Application.Current.Host.Content.ActualWidth - 60;
            double ScreenHeight = System.Windows.Application.Current.Host.Content.ActualHeight - 100;
            
            // Коеффициент, отвечающий за количесвто ячеек и частично за размер шрифта
            int kolich = 30;
    
            // Размер шрифта задается по формуле kolich + addingFontSize.
            int addingFontSize = -2;
    
            // Количество смены символов в ячейке
            int countSymbol = 3;
    
            // Включить (false), выключить (true) матрицу
            bool flagOnOff = false;
    
            // Включить (false), выключить (true) "поворот экрана"
            bool turnOnOff = true;
    
            // Количество строк и столбцов
            int countWidth = 10;
            int countHeight = 10;
    
            // Словарь, в котором хранятся идентификаторы языка и соответствующие ему ASCII коды символов
            Dictionary<string, int[]> languages = new Dictionary<string, int[]>();
    
            // Задаю язык по-умолчанию
            string actualLanguage = "Русский";
    
            // Флаг, отвечающий за показывать (true) / не показывать (false) всплывающее окно (PopUp) при выборе языка
            bool flagShowLanguages = true;
    
            // Цвет фона матрицы, ARGB
            Dictionary<string, int> colorMatrixBackground = new Dictionary<string, int>();
    
            // Цвет первого символа, ARGB
            Dictionary<string, int> colorFirstSymbol = new Dictionary<string, int>();
    
            // Цвет градиента змейки от (второй символ) - до (последний символ), ARGB
            Dictionary<string, int> gradientFrom = new Dictionary<string, int>();
            Dictionary<string, int> gradientTo = new Dictionary<string, int>();
    


    Рассмотри конструктор класса:
    Код. Конструктор класса
            // Конструктор
            public MainPage()
            {
                InitializeComponent();
    
                // Вызываем функцию настройки начальных значений цветов фона, символов и т.д.
                BeginColorSettings();
    
                // Инициализируем список доступных языков, а также соответствующие им ASCII коды символов
                ListLanguages();
    
                // Количество строк и столбцов
                this.countWidth = (int)Math.Round(ScreenWidth / (kolich + addingSize)) + Math.Abs(addingSize);
                this.countHeight = (int)Math.Round(ScreenHeight / (kolich + addingSize)) + 5 + Math.Abs(addingSize);
    
                // Создание сетки элементов, в которой будет сыпаться матрица
                CreateElement();
    
                // Подсвечиваем кнопку Вкл или Выкл,  зависит от флага
                if (this.flagOnOff)
                {
                    Button_Stop.Background = new SolidColorBrush(Colors.Cyan);
                    Button_Start.Background = new SolidColorBrush(Colors.Black);
                }
                else
                {
                    Button_Stop.Background = new SolidColorBrush(Colors.Black);
                    Button_Start.Background = new SolidColorBrush(Colors.Cyan);
                }
    
                // Меняем цвет фона матрицы
                ChangeBackground();
            }
    


    Давайте начнем с выбора цвета. Для начала инициализируем настройки по умолчанию в методе BeginColorSettings();
    Код. BeginColorSettings

            // Начальные настройки цветов фона, символов и т.д
            private void BeginColorSettings()
            {
                // Задаем начальный цвет фона матрицы
                colorMatrixBackground["A"] = 0;
                colorMatrixBackground["R"] = 0;
                colorMatrixBackground["G"] = 0;
                colorMatrixBackground["B"] = 0;
    
                // Задаем начальный цвет первого символа
                colorFirstSymbol["A"] = 255;
                colorFirstSymbol["R"] = 248;
                colorFirstSymbol["G"] = 248;
                colorFirstSymbol["B"] = 255;
    
                // Задаем начальный цвет градиента от (второго символа в змейке)
                gradientFrom["A"] = 255;
                gradientFrom["R"] = 1;
                gradientFrom["G"] = 255;
                gradientFrom["B"] = 1;
    
                // Задаем начальный цвет градиента до (последнего символа в змейке)
                gradientTo["A"] = 0;
                gradientTo["R"] = 0;
                gradientTo["G"] = 0;
                gradientTo["B"] = 0;
            }
    


    Цвет фона матрицы

    Задаем цвет фона. Просто присваиваем соответствующему атрибуту цвет, состоящий из компонент ARGB. Почему четыре составляющие? Прозрачность (А) нам будет нужна для создания эффекта затухания.
    Код. ChangeBackground

            // Метод изменения цвета фона матрицы. По умолчанию черный.
            private void ChangeBackground()
            {
                // Задаю цвет фона матрицы
                LayoutRootSecond.Background = new SolidColorBrush(new Color()
                {
                    A = (byte)(colorMatrixBackground["A"]) /*Opacity*/,
                    R = (byte)(colorMatrixBackground["R"]) /*Red*/,
                    G = (byte)(colorMatrixBackground["G"]) /*Green*/,
                    B = (byte)(colorMatrixBackground["B"]) /*Blue*/
                });
            }
    


    Однако это просто метод. Для того, что б цвет действительно поменялся, нужно забрать его из контролла ColorPicker, присвоить свойству и вызвать метод ChangeBackground:

    Код. Event_Button_Click_ChangeBackground

            // Меняем цвет фона матрицы
            private void Event_Button_Click_ChangeBackground(object sender, RoutedEventArgs e)
            {
                // Передаем в свойство класса colorMatrixBackground выбранный цвет из элемента ColorPicker для фона матрицы
                colorMatrixBackground["A"] = ColorPicker.Color.A;
                colorMatrixBackground["R"] = ColorPicker.Color.R;
                colorMatrixBackground["G"] = ColorPicker.Color.G;
                colorMatrixBackground["B"] = ColorPicker.Color.B;
    
                // Задаем выбранный цвет фона матрицы соответствующей кнопке
                Button_BackgroundColor.Background = new SolidColorBrush(new Color()
                {
                    A = (byte)(colorMatrixBackground["A"]) /*Opacity*/,
                    R = (byte)(colorMatrixBackground["R"]) /*Red*/,
                    G = (byte)(colorMatrixBackground["G"]) /*Green*/,
                    B = (byte)(colorMatrixBackground["B"]) /*Blue*/
                });
    
                // Задаем выбранный цвет фона матрицы
                ChangeBackground();
            }
    


    Цвет первого символа змейки

    Изменим цвет первого символа змейки. Первый символ змейки вызывается в методе RandomElementQ_Async асинхронно:
                        // Вызываем на прорисовку первый, самый яркий падающий элемент. Асинхронно.
                        // colorFirstSymbol["A"]. Цвет задается через настройку.                   
                        await Change(element, timeOut, colorFirstSymbol);
    

    Код. Event_Button_Click_FirstSymbolColor

            // Изменение цвета первого символа
            private void Event_Button_Click_FirstSymbolColor(object sender, RoutedEventArgs e)
            {
                // Передаем в свойство класса colorFirstSymbol выбранный цвет из элемента ColorPicker для фона матрицы
                colorFirstSymbol["A"] = ColorPicker.Color.A;
                colorFirstSymbol["R"] = ColorPicker.Color.R;
                colorFirstSymbol["G"] = ColorPicker.Color.G;
                colorFirstSymbol["B"] = ColorPicker.Color.B;
    
                // Задаем выбранный цвет фона матрицы соответствующей кнопке
                Button_FirstSymbolColor.Background = new SolidColorBrush(new Color()
                {
                    A = (byte)(colorFirstSymbol["A"]) /*Opacity*/,
                    R = (byte)(colorFirstSymbol["R"]) /*Red*/,
                    G = (byte)(colorFirstSymbol["G"]) /*Green*/,
                    B = (byte)(colorFirstSymbol["B"]) /*Blue*/
                });
            }
    


    Задание цветов для градиента

    Ну вот и добрались до градиента. Первое, что нужно сделать — это в обработчиках событий соответствующих кнопок сохранить цвет в свойства класса:
    Код. Event_Button_Click_Gradient
            // Настройки. Задаем градиент змейки. Цвет второго символа.
            private void Event_Button_Click_GradientFrom(object sender, RoutedEventArgs e)
            {
                // Передаем в свойство класса gradientFrom выбранный цвет из элемента ColorPicker для фона матрицы
                gradientFrom["A"] = ColorPicker.Color.A;
                gradientFrom["R"] = ColorPicker.Color.R;
                gradientFrom["G"] = ColorPicker.Color.G;
                gradientFrom["B"] = ColorPicker.Color.B;
    
                // Задаем выбранный цвет градиента от змейки соответствующей кнопке
                Button_GradientFrom.Background = new SolidColorBrush(new Color()
                {
                    A = (byte)(gradientFrom["A"]) /*Opacity*/,
                    R = (byte)(gradientFrom["R"]) /*Red*/,
                    G = (byte)(gradientFrom["G"]) /*Green*/,
                    B = (byte)(gradientFrom["B"]) /*Blue*/
                });
            }
    
             / Настройки. Задаем градиент змейки. Цвет последнего символа.
            private void Event_Button_Click_GradientTo (object sender, RoutedEventArgs e)
            {
                // Передаем в свойство класса gradientTo выбранный цвет из элемента ColorPicker для фона матрицы
                gradientTo["A"] = ColorPicker.Color.A;
                gradientTo["R"] = ColorPicker.Color.R;
                gradientTo["G"] = ColorPicker.Color.G;
                gradientTo["B"] = ColorPicker.Color.B;
    
                // Задаем выбранный цвет градиента до змейки соответствующей кнопке
                Button_GradientTo.Background = new SolidColorBrush(new Color()
                {
                    A = (byte)(gradientTo["A"]) /*Opacity*/,
                    R = (byte)(gradientTo["R"]) /*Red*/,
                    G = (byte)(gradientTo["G"]) /*Green*/,
                    B = (byte)(gradientTo["B"]) /*Blue*/
                });
            }     
    


    Теперь эти цвета нужно применить к нашим символам. Переходим в метод RandomElementQ_Async и немножко меняем ту часть, которая отвечает за расчет яркости и цвета символов следующим образом:
    Код. RandomElementQ_Async и Change
    Меняем
    //int greenCoefficient = (int)Math.Round(255 / (double)(count + 1)) - 1;
    

    на
                        int A_Coefficient = (int)Math.Round((gradientFrom["A"] - 10) / (double)(count + 1)) - 1;
                        int R_Coefficient = (int)Math.Round((gradientFrom["R"] - gradientTo["R"]) / (double)(count + 1)) - 1;
                        int G_Coefficient = (int)Math.Round((gradientFrom["G"] - gradientTo["G"]) / (double)(count + 1)) - 1;
                        int B_Coefficient = (int)Math.Round((gradientFrom["B"] - gradientTo["B"]) / (double)(count + 1)) - 1;
    

    А так же перед вызовом Task dsvv = Change(previousElement, timeOut, SymbolColor); добавляем:
                                // Вызываем извлеченные элементы
                                // (greenCoefficient * (k + 1)) - 20 Высчитываем яркость так, что б разница между первым и последним была на всех змейках одинаковая
                                // и равномерно распределялась независимо от ее длины(количества элементов)
                                SymbolColor["A"] = (gradientFrom["A"] - ((i - k) * A_Coefficient));
                                SymbolColor["R"] = (gradientFrom["R"] - ((i - k) * R_Coefficient));
                                SymbolColor["G"] = (gradientFrom["G"] - ((i - k) * G_Coefficient));
                                SymbolColor["B"] = (gradientFrom["B"] - ((i - k) * B_Coefficient));
    

    И меняем определение метода Change, где вместо int Opacity ставим Dictionary<string, int> SymbolColor:
     // Метод изменения символов в заданном элеменете
            public async Task Change(TextBlock element, int timeOut, Dictionary<string, int> SymbolColor)
    

    А внутри этого метода задаем цвет символа с помощью новых значений. Меняем
                // Формируем нужный цвет с заданной яркостью
                SolidColorBrush NewColor = new SolidColorBrush(new Color()
                {
                    A = (byte)(255) /*Opacity*/,
                    R = (byte)(0) /*Red*/,
                    G = (byte)(Opacity) /*Green*/,
                    B = (byte)(0) /*Blue*/
                });
    

    на
                // Формируем нужный цвет с заданной яркостью
                SolidColorBrush NewColor = new SolidColorBrush(new Color()
                {
                    A = (byte)(SymbolColor["A"]) /*Opacity*/,
                    R = (byte)(SymbolColor["R"]) /*Red*/,
                    G = (byte)(SymbolColor["G"]) /*Green*/,
                    B = (byte)(SymbolColor["B"]) /*Blue*/
                });
    


    Выбор языка

    С цветами разобрались. Теперь давайте решим вопрос с выбором языка. В конструкторе класса мы вызывали метод ListLanguages для инициализации доступных языков. Рассмотрим его более подробно:
    Код. ListLanguages
            // Заполняем словарь идентификаторами языка и соответствующие ему ASCII коды символов
            public void ListLanguages()
            {
                // Добавляем в словарь ключь -  название языка и значение -  массив, состоящий из ASCII кодов символов.
                languages.Add("Матрица", new int[] { 64, 127 });
                languages.Add("Китаский", new int[] { 19968, 20223 });
                languages.Add("Английский", new int[] { 64, 127 });
                languages.Add("Цифры", new int[] { 48, 57 });
                languages.Add("Случайные символы", new int[] { 0, 1000 });
                languages.Add("Русский", new int[] { 1040, 1103 });
    
                // Добавляем языки в всплывающую панель для возможности их выбора
                foreach (var language in languages)
                {
                    // Создаю кнопку
                    Button newLang = new Button();
    
                    // Задаю надпись кнопки, соответствует языку
                    newLang.Content = language.Key.ToString();
    
                    // Горизонтальное выравнивание
                    newLang.HorizontalAlignment = HorizontalAlignment.Stretch;
    
                    // Толщина рамки
                    newLang.BorderThickness = new Thickness(1);
    
                    // Смещение
                    newLang.Margin = new Thickness(0,0,0,0);
    
                    // Событие, при нажатии на кнопку. Одно на все.
                    newLang.Click += Event_Button_Click_SelectLanguageUpdate;
    
                    // Добавляю созданую и настроенную кнопку в всплывающее окно
                    StackPanel_ButtonDropDownSelectLanguage.Children.Add(newLang);
                }
            }
    


    Теперь добавляем обработчик кнопки, в которой показывается выбранный язык и при нажатии на которую появляется всплывающее окно:
    Код. Event_Button_Click_SelectLanguage
            // Кнопка, в которой показывается текущее выбранное значение языка. при нажатии на нее всплывает меню для выбора другого языка.
            private void Event_Button_Click_SelectLanguage(object sender, RoutedEventArgs e)
            {
                // Показывать (true) / не показывать (false) всплывающее окно (PopUp) при выборе языка
                if (flagShowLanguages)
                {
                    // Показать всплывающее окно
                    Popup_ButtonDropDownSelectLanguage.IsOpen = true;
                    flagShowLanguages = false;
                }
                else
                {
                    // Скрыть всплывающее окно
                    Popup_ButtonDropDownSelectLanguage.IsOpen = false;
                    flagShowLanguages = true;
                }
            }
    


    В сплывающем окне находятся кнопки, при нажатии на которые и выбирается нужный язык. У всех кнопок назначен один и тот же обработчик событий, который определяет контент кнопки, который и является ключом в словаре для выбора языка. Задаем значение выбранного языка в свойство класса actualLanguage:
    Код. Event_Button_Click_SelectLanguageUpdate
            // Всплывающее меню выбора языка.
            private void Event_Button_Click_SelectLanguageUpdate(object sender, RoutedEventArgs e)
            {
                // Если нажата кнопка выбора языка, но другой язык не выбран, то при повторном нажатии меню свернется. 
                if (!flagShowLanguages)
                {
                    // Скрыть всплывающее окно
                    Popup_ButtonDropDownSelectLanguage.IsOpen = false;
                    flagShowLanguages = true;
                }
    
                // Получаем название кнопки, которую нажали
                string newLanguagr = (sender as Button).Content.ToString();
    
                // Обновляем название кнопки, отображающей выбранный язык
                Button_SelectLanguage.Content = newLanguagr;
    
                // Задаем значение языка, в котором выбирать символы случайным образом
                this.actualLanguage = newLanguagr;
            }
    


    Теперь все готово, для того, что б можно было выбрать случайный символ из заданного диапазона. Напишем метод RandomActualSymbol, который и будет возвращать случайный символ:
    Код. RandomActualSymbol
            // Вызываем эту функцию везде, где нужно показать случайный символ из выбранного языка.
            public string RandomActualSymbol()
            {
                // Получаем массив по ключу, содержащий ASCII коды символов языка, заданного в actualLanguage
                int[] sd = (languages[actualLanguage]);
    
                // Выбираем случайнфй символ в диапазоне от первого до последнего символа в заданом языке
                return char.ConvertFromUtf32(this.random.Next((int)sd.GetValue(0), (int)sd.GetValue(1)));
            }
    


    И подставим вызов этого метода везде, где нужно задать символ. Например, в методе Change:
                    // Каждый раз разный символ из заданного диапазона
                    element.Text = RandomActualSymbol();   
    

    Старт / Стоп

    Тут все очень просто. В зависимости от флага flagOnOff, который задан как свойство класса завершаем циклы, в которых происходит обработка непосредственно самой матрицы.
    Задаем обработчики событий кнопок «Старт» и «Стоп», которые просто меняют состояние флага на противоположный:
    Код. Event_Button_Click_Stop и Event_Button_Click_Start
            // Настройки. Выключаем возможность анимирования змеек
            private void Event_Button_Click_Stop(object sender, RoutedEventArgs e)
            {
                this.flagOnOff = true;
    
                // Если flagOnOff в true то подсвечиваем кнопку Stop
                if (this.flagOnOff)
                {
                    Button_Stop.Background = new SolidColorBrush(Colors.Cyan);
                    Button_Start.Background = new SolidColorBrush(Colors.Black);
                }
            }
    
            // Настройки. Включаем возможность анимирования змеек
            private void Event_Button_Click_Start(object sender, RoutedEventArgs e)
            {
                this.flagOnOff = false;
    
                // Если flagOnOff в false то подсвечиваем кнопку Start
                if (!this.flagOnOff)
                {
                    Button_Stop.Background = new SolidColorBrush(Colors.Black);
                    Button_Start.Background = new SolidColorBrush(Colors.Cyan);
                }
            }
    


    И добавляем внутри нескольких циклов простое условие
     if (flagOnOff) break;
    

    А именно в циклах методов Event_Grid_Tap_LayoutRoot, RandomElementQ_Async, Change:
    Код. Остановка матрицы
    В Event_Grid_Tap_LayoutRoot:
                // Количество одновременно появляющихся змеек после нажатия
                for (int i = 0; i < countSimultaneously; i++)
                {
                    // Останавливаем анимацию
                    if (flagOnOff) break;
    

    В RandomElementQ_Async тут:
    
                // Цикл формирует змейку заданной длины length
                for (int i = 0; i <= length; i++)
                {
                    // Останавливаем анимацию
                    if (flagOnOff) break;
    

    и тут:
                        // Перебираем все  элементы, составляющие змейку на данном этапе. С каждым циклом она увеличивается, пока не достигнет нужной длины.
                        for (int k = 0; k <= i; k++)
                        {                       
                            // Останавливаем анимацию
                            if (flagOnOff) break;
    

    В Change:
                // Количество смены символов в каждой ячейке
                for (int i = 0; i < countSymbol; i++)
                {
                    // Останавливаем анимацию
                    if (flagOnOff) break;
    


    Почему аж в четырех местах? Если змеек мало, то все нормально. Но если количество змеек неприлично большое, например, 50+, то матрица останавливается с заметными тормозами. А так мы останавливаем непосредственно каждый элемент, принимающий участие в работе механизма матрицы.
    Ну и напоследок добавим красоты, для задания цвета кнопки, которая сейчас нажата. В конструкторе за это отвечает этот код:
                // Подсвечиваем кнопку Вкл или Выкл,  зависит от флага
                if (this.flagOnOff)
                {
                    Button_Stop.Background = new SolidColorBrush(Colors.Cyan);
                    Button_Start.Background = new SolidColorBrush(Colors.Black);
                }
                else
                {
                    Button_Stop.Background = new SolidColorBrush(Colors.Black);
                    Button_Start.Background = new SolidColorBrush(Colors.Cyan);
                }
    

    Точнее сказать, задания цвета кнопки при инициализации приложения.

    Очистка экрана

    При срабатывании события Event_Button_Click_Clear происходит тоже самое, что и в CreateElement, только без создания элементов. Перебираются все элементы и как символ задается пустота:
    Код. Event_Button_Click_Clear
            // Настройки. Очистка экрана
            private void Event_Button_Click_Clear(object sender, RoutedEventArgs e)
            {
                // Перебираем сетку ячеек и устанавливаем в каждой ячейке как символ - пустоту
                for ( int i = 0; i < countWidth; i++)
                {
                    for (int j = 0; j < countHeight; j++)
                    {
                        // Формируем имя элемента, который будем очищать
                        string elementName = "TB_" + i + "_" + j;
    
                        // Получаем элемент по его имени
                        object wantedNode = LayoutRoot.FindName(elementName);
                        TextBlock element = (TextBlock)wantedNode;
    
                        // Очищаем значение
                        element.Text = "";
                    }
                }
            }
    


    Горизонтальная / Вертикальная ориентация

    Опять все исходит от флага turnOnOff. Что мы делаем? Останавливаем матрицу. Меняем надпись на кнопке. Меняем местами количество строк и столбцов. Удаляем матрицу. Создаем матрицу снова, вызывая метод CreateElement:
    Код. Event_Button_Click_Turn
            // Настройки. Вериткальная / горизонтальная матрица
            private void Event_Button_Click_Turn(object sender, RoutedEventArgs e)
            {
                // Включить (true), выключить (false) "поворот экрана"
                if (turnOnOff)
                {
                    // Сохраняем значение false в свойство класса turnOnOff
                    this.turnOnOff = false;
    
                    // Надпись на конопке с именем ToggleButton_Turn меняю на Горизонтально
                    ToggleButton_Turn.Content = "Горизонтально";
    
                    // Количество строк и столбцов. Инвертируем для горизонтали.
                    this.countHeight = (int)Math.Round(ScreenWidth / (kolich + addingSize)) + 5 + Math.Abs(addingSize);
                    this.countWidth = (int)Math.Round(ScreenHeight / (kolich + addingSize)) + 5 + Math.Abs(addingSize);
                }
                else
                {
                    // Сохраняем значение true в свойство класса turnOnOff
                    this.turnOnOff = true;
    
                    // Надпись на конопке с именем ToggleButton_Turn меняю на Вертикально
                    ToggleButton_Turn.Content = "Вертикально";
    
                    // Количество строк и столбцов. Возвращаем для вертикали
                    this.countWidth = (int)Math.Round(ScreenWidth / (kolich + addingSize)) + Math.Abs(addingSize);
                    this.countHeight = (int)Math.Round(ScreenHeight / (kolich + addingSize)) + 5 + Math.Abs(addingSize);
                }
    
                // Останавливаем матрицу
                this.flagOnOff = true;
    
                // Удаляем матрицу (сами ячейки)
                LayoutRootSecond.Children.Clear();
    
                // Перерисовываем ячейки заново с новыми параметрами
                CreateElement();
    
                // Включаем матрицу
                this.flagOnOff = false;
            }
    


    Изменение размера матрицы

    Логика схожа с поворотом. Единственная разница в том, что мы не меняем местами количество строк и столбцов, а добавляем к расчету количества строк и столбцов коэффициент, введенный пользователем:
    Код. Event_Button_Click_ElementSize
            // Настройки. Размер клетки для символа
            private void Event_Button_Click_ElementSize(object sender, RoutedEventArgs e)
            {
                // Сохраняем значение их соответствующего TextBox TextBox_ElementSize в свойство класса addingSize
                this.addingSize = int.Parse(TextBox_ElementSize.Text.ToString());
    
                // Количество строк и столбцов. Возвращаем для вертикали
                this.countWidth = (int)Math.Round(ScreenWidth / (kolich + addingSize)) + Math.Abs(addingSize);
                this.countHeight = (int)Math.Round(ScreenHeight / (kolich + addingSize)) + 5 + Math.Abs(addingSize);
    
                // Останавливаем матрицу
                this.flagOnOff = true;
    
                // Удаляем матрицу (сами ячейки)
                LayoutRootSecond.Children.Clear();
    
                // Перерисовываем ячейки заново с новыми параметрами
                CreateElement();
    
                // Включаем матрицу
                this.flagOnOff = false;
            }
    


    Остальные настройки

    Выполнены по одному шаблону. Получаем введенное пользователем значение, записываем его в соответствующее свойство класса, которое и подставляем в нужном месте, вместо статических значений которые были в предыдущей части.
    Например количество одновременно ползущих змеек:
    Код. Event_Grid_Tap_LayoutRoot
    Вместо статики
            // Событие при нажатии на эелемет Grid (на экран)
            private void Event_Grid_Tap_LayoutRoot(object sender, System.Windows.Input.GestureEventArgs e)
            {
                // Количество одновременно появляющихся змеек после нажатия
                for (int i = 0; i < 5; i++)
                {
                    // Останавливаем анимацию
                    if (flagOnOff) break;
    
                    Start();
    
                    //Задержка между вызовами. Для красоты матрицы.
                    Task.Delay(100);
                }
            }
    

    Делаем динамику:
            // Событие при нажатии на эелемет Grid (на экран)
            private void Event_Grid_Tap_LayoutRoot(object sender, System.Windows.Input.GestureEventArgs e)
            {
                // Количество одновременно появляющихся змеек после нажатия
                for (int i = 0; i < countSimultaneously; i++)
                {
                    // Останавливаем анимацию
                    if (flagOnOff) break;
    
                    Start();
    
                    //Задержка между вызовами. Для красоты матрицы.
                    Task.Delay(100);
                }
            }
    


    Код. MainPage.xaml.cs
    using System;
    using System.Net;
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Navigation;
    using Microsoft.Phone.Controls;
    using Microsoft.Phone.Shell;
    using System.Windows.Media;
    using System.Threading.Tasks;
    using System.Diagnostics;
    using System.Collections.ObjectModel;
    
    namespace SE_Matrix_2d_v_4
    {
        public partial class MainPage : PhoneApplicationPage
        {
            /* ****************************** Свойства класса ****************************** */
            // Случайное число
            Random random = new Random();
    
            // Количество змеек после нажатия на экран в очереди
            int iteration = 5;
    
            // Количество одновременно появляющихся змеек после нажатия
            int countSimultaneously = 3;
    
            // Скорость смены символов
            int speedFrom = 20;
            int speedTo = 40;
    
            // Размер клетки для символа
            int addingSize = -6;
    
            // Итоговый размер шрифта
            int fontSize;
    
            // Минимальная и максимальная длина змейки
            int minLength = 10;
            int maxLength = 15;
    
            // Получаем расширение экрана
            double ScreenWidth = System.Windows.Application.Current.Host.Content.ActualWidth - 60;
            double ScreenHeight = System.Windows.Application.Current.Host.Content.ActualHeight - 100;
            
            // Коеффициент, отвечающий за количесвто ячеек и частично за размер шрифта
            int kolich = 30;
    
            // Размер шрифта задается по формуле kolich + addingFontSize.
            int addingFontSize = -2;
    
            // Количество смены символов в ячейке
            int countSymbol = 3;
    
            // Включить (false), выключить (true) матрицу
            bool flagOnOff = false;
    
            // Включить (false), выключить (true) "поворот экрана"
            bool turnOnOff = true;
    
            // Количество строк и столбцов
            int countWidth = 10;
            int countHeight = 10;
    
            // Словарь, в котором хранятся идентификаторы языка и соответствующие ему ASCII коды символов
            Dictionary<string, int[]> languages = new Dictionary<string, int[]>();
    
            // Задаю язык по-умолчанию
            string actualLanguage = "Русский";
    
            // Флаг, отвечающий за показывать (true) / не показывать (false) всплывающее окно (PopUp) при выборе языка
            bool flagShowLanguages = true;
    
            // Цвет фона матрицы, ARGB
            Dictionary<string, int> colorMatrixBackground = new Dictionary<string, int>();
    
            // Цвет первого символа, ARGB
            Dictionary<string, int> colorFirstSymbol = new Dictionary<string, int>();
    
            // Цвет градиента змейки от (второй символ) - до (последний символ), ARGB
            Dictionary<string, int> gradientFrom = new Dictionary<string, int>();
            Dictionary<string, int> gradientTo = new Dictionary<string, int>();
            
            /* ****************************** Методы класса ****************************** */
            // Конструктор
            public MainPage()
            {
                InitializeComponent();
    
                // Вызываем функцию настройки начальных значений цветов фона, символов и т.д.
                BeginColorSettings();
    
                // Инициализируем список доступных языков, а также соответствующие им ASCII коды символов
                ListLanguages();
    
                // Количество строк и столбцов
                this.countWidth = (int)Math.Round(ScreenWidth / (kolich + addingSize)) + Math.Abs(addingSize);
                this.countHeight = (int)Math.Round(ScreenHeight / (kolich + addingSize)) + 5 + Math.Abs(addingSize);
    
                // Создание сетки элементов, в которой будет сыпаться матрица
                CreateElement();
    
                // Подсвечиваем кнопку Вкл или Выкл,  зависит от флага
                if (this.flagOnOff)
                {
                    Button_Stop.Background = new SolidColorBrush(Colors.Cyan);
                    Button_Start.Background = new SolidColorBrush(Colors.Black);
                }
                else
                {
                    Button_Stop.Background = new SolidColorBrush(Colors.Black);
                    Button_Start.Background = new SolidColorBrush(Colors.Cyan);
                }
    
                // Меняем цвет фона матрицы
                ChangeBackground();
            }
    
            // Создание сетки элементов, в которой будет сыпаться матрица
            public void CreateElement()
            {
                // Вычисляем тоговый размер шрифта для разметки / переразметки
                this.fontSize = kolich + addingFontSize + addingSize;
    
                // Создаем сетку ячеек
                for (int i = 0; i < countWidth; i++)
                {
                    for (int j = 0; j < countHeight; j++)
                    {
                        // Создаем TextBlock
                        TextBlock element = new TextBlock();
    
                        // Задаем имя элемента TextBlock
                        element.Name = "TB_" + i + "_" + j;
    
                        // Задаем начальный символ при инициализации сетки ячеек
                        // element.Text = char.ConvertFromUtf32(random.Next(0x4E00, 0x4FFF)); // Случайный символ из заданного диапазона
                        // element.Text = random.Next(0, 9).ToString(); // Случайным числом
                        element.Text = ""; // Пустота
    
                        // Задаем смещение каждого нового элемента TextBlock
                        // Также отвечает за разворот вертикальный / горизонтальный
                        int turnY = j * (kolich + addingSize);
                        int turnX = i * (kolich + addingSize);
    
                        // Включить (false), выключить (true) "поворот экрана"
                        if (turnOnOff)
                        {
                            // Вертикальное, стандартное расположение
                            element.Margin = new Thickness(turnX, turnY, 0, 0);
                        }
                        else
                        {
                            // Повернутое, горизонтальное расположение
                            element.Margin = new Thickness(turnY, turnX, 0, 0);
                        }
    
                        // Задаем цвет символа
                        element.Foreground = new SolidColorBrush(Colors.Green);
    
                        // Задаем размер шрифта
                        element.FontSize = fontSize;
    
                        // Добавляем созданный элемент в Grid
                        LayoutRootSecond.Children.Add(element);
                    }
                }
            }
    
            // Событие при нажатии на эелемет Grid (на экран)
            private void Event_Grid_Tap_LayoutRoot(object sender, System.Windows.Input.GestureEventArgs e)
            {
                // Количество одновременно появляющихся змеек после нажатия
                for (int i = 0; i < countSimultaneously; i++)
                {
                    // Останавливаем анимацию
                    if (flagOnOff) break;
    
                    Start();
    
                    //Задержка между вызовами. Для красоты матрицы.
                    Task.Delay(100);
                }
            }
    
            // Метод запуска змейки
            public async void Start()
            {
                int count;
    
                // Количество змеек после нажатия на экран в очереди
                for (count = 0; count < iteration; count++)
                {
                    // Начало змейки по горизонтали случайным образом
                    int ranX = random.Next(0, countWidth);
    
                    // Начало змейки по вертикали случайным образом
                    int ranY = random.Next(-5, countHeight - 1);
    
                    // Длина змейки случайным образом
                    int length = random.Next(minLength, maxLength);
    
                    // Скорость смены символов в змейке случайным образом
                    int time = random.Next(speedFrom, speedTo);
    
                    await Task.Delay(1);
                    
                    //Обработка змейки
                    await RandomElementQ_Async(ranX, ranY, length, time);
                }
            }
    
            // Определяю элемент, в котором нужно менять символы
            public async Task RandomElementQ_Async(int x, int y, int length, int timeOut)
            {
                // Словарь для хранения идентификаторов ячеек, которые вызывались на предыдущем этапе.
                Dictionary<int, TextBlock> dicElem = new Dictionary<int, TextBlock>();
    
                // Задаем цвет символов
                Dictionary<string, int> SymbolColor = new Dictionary<string, int>();
    
                // Счетчик, нужен для обработки случаев, когда не выполняется условие if ((y + i) < countHeight && (y + i) >= 0). Смотри на 4 строчки вниз.
                // Тоесть элемент в котором нужно менять символы выше или ниже нашей сетки (матрицы элементов).
                int count = 0;
    
                // Цикл формирует змейку заданной длины length
                for (int i = 0; i <= length; i++)
                {
                    // Останавливаем анимацию
                    if (flagOnOff) break;
    
                    //Проверяем, что б змейка отображалась только в координатах, которые существуют в нашей сетке
                    if ((y + i) < countHeight && (y + i) >= 0)
                    {
                        // Формируем имя элемента, в котором будут меняться символы
                        string elementName = "TB_" + x + "_" + (y + i);
    
                        // Получаем элемент по его имени
                        object wantedNode = LayoutRoot.FindName(elementName);
                        TextBlock element = (TextBlock)wantedNode;
    
                        // Отправляем элемент в словарь, из которого он будет извлекаться для эффекта "падения" и "затухания" змейки
                        dicElem[count] = (element);
    
                        // Определяем коеффициент для подсчета яркости. Первый элемент(который падает) -  всега самый яркий, последний - самый темный.
                        // Отнимаем 1, потому, что последний элемент (когда к -  максимальное) в итоге получается больше 255 и становится ярким.
                        int A_Coefficient = (int)Math.Round((gradientFrom["A"] - 10) / (double)(count + 1)) - 1;
                        int R_Coefficient = (int)Math.Round((gradientFrom["R"] - gradientTo["R"]) / (double)(count + 1)) - 1;
                        int G_Coefficient = (int)Math.Round((gradientFrom["G"] - gradientTo["G"]) / (double)(count + 1)) - 1;
                        int B_Coefficient = (int)Math.Round((gradientFrom["B"] - gradientTo["B"]) / (double)(count + 1)) - 1;
                        //int greenCoefficient = (int)Math.Round(255 / (double)(count + 1)) - 1;
    
                        // Вызываем на прорисовку первый, самый яркий падающий элемент. Асинхронно.
                        // colorFirstSymbol["A"]. Цвет задается через настройку.                   
                        await Change(element, timeOut, colorFirstSymbol);
    
                        // Перебираем все  элементы, составляющие змейку на данном этапе. С каждым циклом она увеличивается, пока не достигнет нужной длины.
                        for (int k = 0; k <= i; k++)
                        {                       
                            // Останавливаем анимацию
                            if (flagOnOff) break;
    
                            // Если змейка начинаеися "выше" начальных координат (например, если y = -5)
                            if (dicElem.ContainsKey(k))
                            {
                                //Извлекаем элементы, которые должны следовать за самым ярким. Создаем эффект "затухания" цвета
                                TextBlock previousElement = dicElem[k];
    
                                // Вызываем извлеченные элементы
                                // (greenCoefficient * (k + 1)) - 20 Высчитываем яркость так, что б разница между первым и последним была на всех змейках одинаковая
                                // и равномерно распределялась независимо от ее длины(количества элементов)
                                SymbolColor["A"] = (gradientFrom["A"] - ((i - k) * A_Coefficient));
                                SymbolColor["R"] = (gradientFrom["R"] - ((i - k) * R_Coefficient));
                                SymbolColor["G"] = (gradientFrom["G"] - ((i - k) * G_Coefficient));
                                SymbolColor["B"] = (gradientFrom["B"] - ((i - k) * B_Coefficient));
    
                                Task dsvv = Change(previousElement, timeOut, SymbolColor);
                            }
                        }
                        count++;
                    }
                }
            }
    
            // Метод изменения символов в заданном элеменете
            public async Task Change(TextBlock element, int timeOut, Dictionary<string, int> SymbolColor)
            {
                // Формируем нужный цвет с заданной яркостью
                SolidColorBrush NewColor = new SolidColorBrush(new Color()
                {
                    A = (byte)(SymbolColor["A"]) /*Opacity*/,
                    R = (byte)(SymbolColor["R"]) /*Red*/,
                    G = (byte)(SymbolColor["G"]) /*Green*/,
                    B = (byte)(SymbolColor["B"]) /*Blue*/
                });
    
                // При каждом "падении" на 1 клеточку равномерно "затухает"
                element.Foreground = NewColor;
    
                // Количество смены символов в каждой ячейке
                for (int i = 0; i < countSymbol; i++)
                {
                    // Останавливаем анимацию
                    if (flagOnOff) break;
    
                    // Каждый раз разный символ из заданного диапазона
                    element.Text = RandomActualSymbol();              
    
                    // Размер шрифта
                    element.FontSize = fontSize;
    
                    // Скорость смены символов в ячейке
                    await Task.Delay(timeOut);
                }
            }
    
            // Загрузка данных для элементов ViewModel
            protected override void OnNavigatedTo(NavigationEventArgs e)
            {
                if (!App.ViewModel.IsDataLoaded)
                {
                    App.ViewModel.LoadData();
                }
            }
    
            /* ****************************** События ****************************** */
            // Настройки. Скорость смены символов.
            private void Event_Button_Click_SpeedApplay(object sender, RoutedEventArgs e)
            {
                // Сохраняем значение их соответствующего TextBox TextBox_SppeedFrom в свойство класса speedFrom
                this.speedFrom = int.Parse(TextBox_SppeedFrom.Text.ToString());
    
                // Сохраняем значение их соответствующего TextBox TextBox_SppeedTo в свойство класса speedTo
                this.speedTo = int.Parse(TextBox_SppeedTo.Text.ToString());
            }
    
            // Настройки. Количество змеек в очереди
            private void Event_Button_Click_CountQueue(object sender, RoutedEventArgs e)
            {
                // Сохраняем значение их соответствующего TextBox TextBox_CountQueue в свойство класса iteration
                this.iteration = int.Parse(TextBox_CountQueue.Text.ToString());
            }
    
            // Настройки. Количество змеек за нажатие
            private void Event_Button_Click_СountSimultaneously(object sender, RoutedEventArgs e)
            {
                // Сохраняем значение их соответствующего TextBox TextBox_СountSimultaneously в свойство класса countSimultaneously
                this.countSimultaneously = int.Parse(TextBox_СountSimultaneously.Text.ToString());
            }
    
            // Настройки. Размер шрифта
            private void Event_Button_Click_FontSize(object sender, RoutedEventArgs e)
            {
                // Сохраняем значение их соответствующего TextBox TextBox_FontSize в свойство класса addingFontSize
                this.addingFontSize = int.Parse(TextBox_FontSize.Text.ToString());
    
                // Вычисляем тоговый размер шрифта для разметки / переразметки
                this.fontSize = kolich + addingFontSize + addingSize;
            }
    
            // Настройки. Количество смены символов в ячейке
            private void Event_Button_Click_CountSymbol(object sender, RoutedEventArgs e)
            {
                // Сохраняем значение их соответствующего TextBox TextBox_CountSymbol в свойство класса countSymbol
                this.countSymbol = int.Parse(TextBox_CountSymbol.Text.ToString());
            }
    
            // Настройки. Выключаем возможность анимирования змеек
            private void Event_Button_Click_Stop(object sender, RoutedEventArgs e)
            {
                this.flagOnOff = true;
    
                // Если flagOnOff в true то подсвечиваем кнопку Stop
                if (this.flagOnOff)
                {
                    Button_Stop.Background = new SolidColorBrush(Colors.Cyan);
                    Button_Start.Background = new SolidColorBrush(Colors.Black);
                }
            }
    
            // Настройки. Включаем возможность анимирования змеек
            private void Event_Button_Click_Start(object sender, RoutedEventArgs e)
            {
                this.flagOnOff = false;
    
                // Если flagOnOff в false то подсвечиваем кнопку Start
                if (!this.flagOnOff)
                {
                    Button_Stop.Background = new SolidColorBrush(Colors.Black);
                    Button_Start.Background = new SolidColorBrush(Colors.Cyan);
                }
            }
    
            // Настройки. Очистка экрана
            private void Event_Button_Click_Clear(object sender, RoutedEventArgs e)
            {
                // Перебираем сетку ячеек и устанавливаем в каждой ячейке как символ - пустоту
                for ( int i = 0; i < countWidth; i++)
                {
                    for (int j = 0; j < countHeight; j++)
                    {
                        // Формируем имя элемента, который будем очищать
                        string elementName = "TB_" + i + "_" + j;
    
                        // Получаем элемент по его имени
                        object wantedNode = LayoutRoot.FindName(elementName);
                        TextBlock element = (TextBlock)wantedNode;
    
                        // Очищаем значение
                        element.Text = "";
                    }
                }
            }
    
            // Настройки. Размер клетки для символа
            private void Event_Button_Click_ElementSize(object sender, RoutedEventArgs e)
            {
                // Сохраняем значение их соответствующего TextBox TextBox_ElementSize в свойство класса addingSize
                this.addingSize = int.Parse(TextBox_ElementSize.Text.ToString());
    
                // Количество строк и столбцов. Возвращаем для вертикали
                this.countWidth = (int)Math.Round(ScreenWidth / (kolich + addingSize)) + Math.Abs(addingSize);
                this.countHeight = (int)Math.Round(ScreenHeight / (kolich + addingSize)) + 5 + Math.Abs(addingSize);
    
                // Останавливаем матрицу
                this.flagOnOff = true;
    
                // Удаляем матрицу (сами ячейки)
                LayoutRootSecond.Children.Clear();
    
                // Перерисовываем ячейки заново с новыми параметрами
                CreateElement();
    
                // Включаем матрицу
                this.flagOnOff = false;
            }
    
            // Настройки. Задаем максимальную и минимальную длину змейки
            private void Event_Button_Click_MaxLength(object sender, RoutedEventArgs e)
            {
                // Сохраняем значение их соответствующего TextBox TextBox_MinLength в свойство класса minLength
                this.minLength = int.Parse(TextBox_MinLength.Text.ToString());
    
                // Сохраняем значение их соответствующего TextBox TextBox_MaxLength в свойство класса maxLength
                this.maxLength = int.Parse(TextBox_MaxLength.Text.ToString());
            }
    
            // Настройки. Вериткальная / горизонтальная матрица
            private void Event_Button_Click_Turn(object sender, RoutedEventArgs e)
            {
                // Включить (true), выключить (false) "поворот экрана"
                if (turnOnOff)
                {
                    // Сохраняем значение false в свойство класса turnOnOff
                    this.turnOnOff = false;
    
                    // Надпись на конопке с именем ToggleButton_Turn меняю на Горизонтально
                    ToggleButton_Turn.Content = "Горизонтально";
    
                    // Количество строк и столбцов. Инвертируем для горизонтали.
                    this.countHeight = (int)Math.Round(ScreenWidth / (kolich + addingSize)) + 5 + Math.Abs(addingSize);
                    this.countWidth = (int)Math.Round(ScreenHeight / (kolich + addingSize)) + 5 + Math.Abs(addingSize);
                }
                else
                {
                    // Сохраняем значение true в свойство класса turnOnOff
                    this.turnOnOff = true;
    
                    // Надпись на конопке с именем ToggleButton_Turn меняю на Вертикально
                    ToggleButton_Turn.Content = "Вертикально";
    
                    // Количество строк и столбцов. Возвращаем для вертикали
                    this.countWidth = (int)Math.Round(ScreenWidth / (kolich + addingSize)) + Math.Abs(addingSize);
                    this.countHeight = (int)Math.Round(ScreenHeight / (kolich + addingSize)) + 5 + Math.Abs(addingSize);
                }
    
                // Останавливаем матрицу
                this.flagOnOff = true;
    
                // Удаляем матрицу (сами ячейки)
                LayoutRootSecond.Children.Clear();
    
                // Перерисовываем ячейки заново с новыми параметрами
                CreateElement();
    
                // Включаем матрицу
                this.flagOnOff = false;
            }
    
            // Заполняем словарь идентификаторами языка и соответствующие ему ASCII коды символов
            public void ListLanguages()
            {
                // Добавляем в словарь ключь -  название языка и значение -  массив, состоящий из ASCII кодов символов.
                languages.Add("Матрица", new int[] { 64, 127 });
                languages.Add("Китаский", new int[] { 19968, 20223 });
                languages.Add("Английский", new int[] { 64, 127 });
                languages.Add("Цифры", new int[] { 48, 57 });
                languages.Add("Случайные символы", new int[] { 0, 1000 });
                languages.Add("Русский", new int[] { 1040, 1103 });
    
                // Добавляем языки в всплывающую панель для возможности их выбора
                foreach (var language in languages)
                {
                    // Создаю кнопку
                    Button newLang = new Button();
    
                    // Задаю надпись кнопки, соответствует языку
                    newLang.Content = language.Key.ToString();
    
                    // Горизонтальное выравнивание
                    newLang.HorizontalAlignment = HorizontalAlignment.Stretch;
    
                    // Толщина рамки
                    newLang.BorderThickness = new Thickness(1);
    
                    // Смещение
                    newLang.Margin = new Thickness(0,0,0,0);
    
                    // Событие, при нажатии на кнопку. Одно на все.
                    newLang.Click += Event_Button_Click_SelectLanguageUpdate;
    
                    // Добавляю созданую и настроенную кнопку в всплывающее окно
                    StackPanel_ButtonDropDownSelectLanguage.Children.Add(newLang);
                }
            }
    
            // Вызываем эту функцию везде, где нужно показать случайный символ из выбранного языка.
            public string RandomActualSymbol()
            {
                // Получаем массив по ключу, содержащий ASCII коды символов языка, заданного в actualLanguage
                int[] sd = (languages[actualLanguage]);
    
                // Выбираем случайнфй символ в диапазоне от первого до последнего символа в заданом языке
                return char.ConvertFromUtf32(this.random.Next((int)sd.GetValue(0), (int)sd.GetValue(1)));
            }
    
            // Кнопка, в которой показывается текущее выбранное значение языка. при нажатии на нее всплывает меню для выбора другого языка.
            private void Event_Button_Click_SelectLanguage(object sender, RoutedEventArgs e)
            {
                // Показывать (true) / не показывать (false) всплывающее окно (PopUp) при выборе языка
                if (flagShowLanguages)
                {
                    // Показать всплывающее окно
                    Popup_ButtonDropDownSelectLanguage.IsOpen = true;
                    flagShowLanguages = false;
                }
                else
                {
                    // Скрыть всплывающее окно
                    Popup_ButtonDropDownSelectLanguage.IsOpen = false;
                    flagShowLanguages = true;
                }
            }
    
            // Всплывающее меню выбора языка.
            private void Event_Button_Click_SelectLanguageUpdate(object sender, RoutedEventArgs e)
            {
                // Если нажата кнопка выбора языка, но другой язык не выбран, то при повторном нажатии меню свернется.
                if (!flagShowLanguages)
                {
                    // Скрыть всплывающее окно
                    Popup_ButtonDropDownSelectLanguage.IsOpen = false;
                    flagShowLanguages = true;
                }
    
                // Получаем название кнопки, которую нажали
                string newLanguagr = (sender as Button).Content.ToString();
    
                // Обновляем название кнопки, отображающей выбранный язык
                Button_SelectLanguage.Content = newLanguagr;
    
                // Задаем значение языка, в котором выбирать символы случайным образом
                this.actualLanguage = newLanguagr;
            }
    
            // Меняем цвет фона матрицы
            private void Event_Button_Click_ChangeBackground(object sender, RoutedEventArgs e)
            {
                // Передаем в свойство класса colorMatrixBackground выбранный цвет из элемента ColorPicker для фона матрицы
                colorMatrixBackground["A"] = ColorPicker.Color.A;
                colorMatrixBackground["R"] = ColorPicker.Color.R;
                colorMatrixBackground["G"] = ColorPicker.Color.G;
                colorMatrixBackground["B"] = ColorPicker.Color.B;
    
                // Задаем выбранный цвет фона матрицы соответствующей кнопке
                Button_BackgroundColor.Background = new SolidColorBrush(new Color()
                {
                    A = (byte)(colorMatrixBackground["A"]) /*Opacity*/,
                    R = (byte)(colorMatrixBackground["R"]) /*Red*/,
                    G = (byte)(colorMatrixBackground["G"]) /*Green*/,
                    B = (byte)(colorMatrixBackground["B"]) /*Blue*/
                });
    
                // Задаем выбранный цвет фона матрицы
                ChangeBackground();
            }
    
            // Метод изменения цвета фона матрицы. По умолчанию черный.
            private void ChangeBackground()
            {
                // Задаю цвет фона матрицы
                LayoutRootSecond.Background = new SolidColorBrush(new Color()
                {
                    A = (byte)(colorMatrixBackground["A"]) /*Opacity*/,
                    R = (byte)(colorMatrixBackground["R"]) /*Red*/,
                    G = (byte)(colorMatrixBackground["G"]) /*Green*/,
                    B = (byte)(colorMatrixBackground["B"]) /*Blue*/
                });
            }
    
            // Начальные настройки цветов фона, символов и т.д
            private void BeginColorSettings()
            {
                // Задаем начальный цвет фона матрицы
                colorMatrixBackground["A"] = 0;
                colorMatrixBackground["R"] = 0;
                colorMatrixBackground["G"] = 0;
                colorMatrixBackground["B"] = 0;
    
                // Задаем начальный цвет первого символа
                colorFirstSymbol["A"] = 255;
                colorFirstSymbol["R"] = 248;
                colorFirstSymbol["G"] = 248;
                colorFirstSymbol["B"] = 255;
    
                // Задаем начальный цвет градиента от (второго символа в змейке)
                gradientFrom["A"] = 255;
                gradientFrom["R"] = 1;
                gradientFrom["G"] = 255;
                gradientFrom["B"] = 1;
    
                // Задаем начальный цвет градиента до (последнего символа в змейке)
                gradientTo["A"] = 0;
                gradientTo["R"] = 0;
                gradientTo["G"] = 0;
                gradientTo["B"] = 0;
            }
    
            // Изменение цвета первого символа
            private void Event_Button_Click_FirstSymbolColor(object sender, RoutedEventArgs e)
            {
                // Передаем в свойство класса colorFirstSymbol выбранный цвет из элемента ColorPicker для фона матрицы
                colorFirstSymbol["A"] = ColorPicker.Color.A;
                colorFirstSymbol["R"] = ColorPicker.Color.R;
                colorFirstSymbol["G"] = ColorPicker.Color.G;
                colorFirstSymbol["B"] = ColorPicker.Color.B;
    
                // Задаем выбранный цвет фона матрицы соответствующей кнопке
                Button_FirstSymbolColor.Background = new SolidColorBrush(new Color()
                {
                    A = (byte)(colorFirstSymbol["A"]) /*Opacity*/,
                    R = (byte)(colorFirstSymbol["R"]) /*Red*/,
                    G = (byte)(colorFirstSymbol["G"]) /*Green*/,
                    B = (byte)(colorFirstSymbol["B"]) /*Blue*/
                });
            }
    
            // Настройки. Задаем градиент змейки. Цвет второго символа.
            private void Event_Button_Click_GradientFrom(object sender, RoutedEventArgs e)
            {
                // Передаем в свойство класса gradientFrom выбранный цвет из элемента ColorPicker для фона матрицы
                gradientFrom["A"] = ColorPicker.Color.A;
                gradientFrom["R"] = ColorPicker.Color.R;
                gradientFrom["G"] = ColorPicker.Color.G;
                gradientFrom["B"] = ColorPicker.Color.B;
    
                // Задаем выбранный цвет градиента от змейки соответствующей кнопке
                Button_GradientFrom.Background = new SolidColorBrush(new Color()
                {
                    A = (byte)(gradientFrom["A"]) /*Opacity*/,
                    R = (byte)(gradientFrom["R"]) /*Red*/,
                    G = (byte)(gradientFrom["G"]) /*Green*/,
                    B = (byte)(gradientFrom["B"]) /*Blue*/
                });
            }
    
            // Настройки. Задаем градиент змейки. Цвет последнего символа.
            private void Event_Button_Click_GradientTo (object sender, RoutedEventArgs e)
            {
                // Передаем в свойство класса gradientTo выбранный цвет из элемента ColorPicker для фона матрицы
                gradientTo["A"] = ColorPicker.Color.A;
                gradientTo["R"] = ColorPicker.Color.R;
                gradientTo["G"] = ColorPicker.Color.G;
                gradientTo["B"] = ColorPicker.Color.B;
    
                // Задаем выбранный цвет градиента до змейки соответствующей кнопке
                Button_GradientTo.Background = new SolidColorBrush(new Color()
                {
                    A = (byte)(gradientTo["A"]) /*Opacity*/,
                    R = (byte)(gradientTo["R"]) /*Red*/,
                    G = (byte)(gradientTo["G"]) /*Green*/,
                    B = (byte)(gradientTo["B"]) /*Blue*/
                });
            }     
        }
    }
    






    Выводы


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

    П.С. Если знаете как лучше сделать на данном этапе — прошу в комментарии. И не забывайте, что приложение создается этапами и будут еще как минимум 2 части… Буду благодарен, если подскажете, как решить проблему на последнем видео, так как панорама сдвигается только, если «хватать» за пределами ScrollViewer.
    • +5
    • 11.7k
    • 6
    Share post

    Similar posts

    Comments 6

      +1
      Круто получилось!
        +2
        <irony> Для «китайского режима» было бы неплохо еще и автоматический перевод, что же пишет программа этими иероглифами</irony>
          0
          Исправьте очепятку в слове «выберите» на скриншоте.
          Автор, пиши еще!
          +2
          А почему бы не выкладывать исходники в публичный репозиторий, например на GitHub, постепенно обновляя? Чтобы можно было сразу в удобной форме открыть и посмотреть проект целиком, а не по кусочкам?

        Only users with full accounts can post comments. Log in, please.