Евгений Колесников 11 bulan lalu
induk
melakukan
035e473096
7 mengubah file dengan 185 tambahan dan 138 penghapusan
  1. 5 3
      articles/t8_binding.md
  2. 132 119
      articles/t8_win_app.md
  3. 35 15
      articles/wpf_resource.md
  4. TEMPAT SAMPAH
      img/task013.png
  5. TEMPAT SAMPAH
      img/wpf_01.png
  6. TEMPAT SAMPAH
      img/wpf_02.png
  7. 13 1
      readme.md

+ 5 - 3
articles/t8_binding.md

@@ -9,7 +9,7 @@
 
 ## Введение в привязку данных
 
-В WPF привязка (**binding**) является мощным инструментом программирования, без которого не обходится ни одно серьёзное приложение.
**WPF** привязка (**binding**) является мощным инструментом программирования, без которого не обходится ни одно серьёзное приложение.
 
 Привязка подразумевает взаимодействие двух объектов: источника и приемника. Объект-приемник создает привязку к определенному свойству объекта-источника. В случае модификации объекта-источника, объект-приемник также будет модифицирован. Например, простейшая форма с использованием привязки:
 
@@ -35,14 +35,16 @@
 {Binding ElementName=Имя_объекта-источника, Path=Свойство_объекта-источника}
 ```
 
-То есть в данном случае у нас элемент **TextBox** (поле ввода) является источником, а **TextBlock** (простой текст) - приемником привязки. Свойство *Text* элемента **TextBlock** привязывается к свойству *Text* элемента **TextBox**. В итоге при осуществлении ввода в текстовое поле синхронно будут происходить изменения в текстовом блоке.
+То есть в данном случае у нас элемент **TextBox** (поле ввода) является источником, а **TextBlock** (простой текст) - приёмником привязки. Свойство *Text* элемента **TextBlock** привязывается к свойству *Text* элемента **TextBox**. В итоге при осуществлении ввода в текстовое поле синхронно будут происходить изменения в текстовом блоке.
 
 ### Работа с привязкой в C#
 
 Ключевым объектом при создании привязки является объект **System.Windows.Data.Binding**. Используя этот объект мы можем получить уже имеющуюся привязку для элемента:
 
 ```cs
-Binding binding = BindingOperations.GetBinding(myTextBlock, TextBlock.TextProperty);
+Binding binding = BindingOperations
+    .GetBinding(myTextBlock, 
+                TextBlock.TextProperty);
 ```
 
 В данном случае получаем привязку для свойства зависимостей _TextProperty_ элемента _myTextBlock_.

+ 132 - 119
articles/t8_win_app.md

@@ -2,7 +2,7 @@
 :----------------:|:----------:|:----------------:
 [Библиотеки классов](./t7_dll.md) | [Содержание](../readme.md#тема-8-оконные-приложения) | [Ресурсы](./wpf_resource.md)
 
-# Обзор типов оконных приложений в C#. Знакомство со структурой проекта WPF/Avalonia. Компоновка. Image. Ресурсы.
+# Обзор типов оконных приложений в `C#`. Знакомство со структурой проекта `WPF/Avalonia`. Компоновка. Image.
 
 >Содрано [отсюда](https://metanit.com/sharp/wpf/1.php)
 
@@ -17,33 +17,31 @@
 
 ## Технологии создания оконных приложений
 
-В C# есть несколько технологий для созданий оконных приложений:
**C#** есть несколько технологий для созданий оконных приложений:
 
 * **Windows Forms** - разработка "классических" приложений Windows, считается устаревшей
 
-    **Windows Forms** — интерфейс программирования приложений (API), отвечающий за графический интерфейс пользователя и являющийся частью *Microsoft .NET Framework*. Данный интерфейс упрощает доступ к элементам интерфейса Microsoft Windows за счет создания обёртки для существующего *Win32 API* в управляемом коде. Причём управляемый код — классы, реализующие API для **Windows Forms**, не зависят от языка разработки.
+    **Windows Forms** — интерфейс программирования приложений (API), отвечающий за графический интерфейс пользователя и являющийся частью *Microsoft .NET Framework*. Данный интерфейс упрощает доступ к элементам интерфейса Microsoft Windows за счет создания обёртки для существующего **Win32 API** в управляемом коде. Причём управляемый код — классы, реализующие API для **Windows Forms**, не зависят от языка разработки.
 
-* WPF (Window Presentation Foundation) - более современный фреймворк для .NET Framework, но заточен только под Windows (отрисовку реализует через **DirectX**)
+* **WPF** (Window Presentation Foundation) - более современный фреймворк для **.NET**, но заточен только под Windows (отрисовку реализует через **DirectX**)
 
-    >Стоит отметить, что *.NET Framework* считается устаревшей технологией и на смену ей пришла кроссплатформенная библиотека *.NET Core*. Для неё есть аналог **WPF** - **Avalonia**, совместимый, на уровне разметки, фреймворк, работающий на **OpenGL**.
+* **UWP** (Universal Windows Platform) - вроде как "последний писк", рассчитанный на разработку универсальных приложений под Windows Phone, Windows 8 и.т.д
 
-* UWP (Universal Windows Platform) - вроде как "последний писк", рассчитанный на разработку универсальных приложений под Windows Phone, Windows 8 и.т.д
-
-**Avalonia** являеся практически калькой с **WPF**, поэтому далее я их рассматриваю одновременно.
+* **Avalonia** являеся практически калькой с **WPF**. Он совместим на уровне разметки, но отрисовка реализована через **OpenGL**.
 
 ## Особенности платформ WPF/Avalonia
 
 Если при создании традиционных приложений на основе **Windows Forms** за отрисовку элементов управления и графики отвечали такие части ОС Windows, как **User32** и **GDI+**, то приложения **WPF** основаны на **DirectX** (**Avalonia**, соответственно, на **OpenGL**). В этом состоит ключевая особенность рендеринга графики: используя **WPF/Avalonia**, значительная часть работы по отрисовке графики, как простейших кнопочек, так и сложных 3D-моделей, ложиться на графический процессор на видеокарте, что также позволяет воспользоваться аппаратным ускорением графики.
 
-Одной из важных особенностей является использование языка декларативной разметки интерфейса XAML, основанного на XML: вы можете создавать насыщенный графический интерфейс, используя или декларативное объявление интерфейса, или код C#, либо совмещать и то, и другое.
+Одной из важных особенностей является использование языка декларативной разметки интерфейса **XAML**, основанного на **XML**: вы можете создавать насыщенный графический интерфейс, используя или декларативное объявление интерфейса, или код **C#**, либо совмещать и то, и другое.
 
 ### Преимущества WPF/Avalonia
 
 Что вам, как разработчику, предлагает **WPF/Avalonia**?
 
-* Использование традиционных языков .NET-платформы - C# для создания логики приложения
+* Использование традиционных языков **.NET**-платформы - **C#** для создания логики приложения
 
-* Возможность декларативного определения графического интерфейса с помощью специального языка разметки XAML, основанном на XML и представляющем альтернативу программному созданию графики и элементов управления, а также возможность комбинировать XAML и C#
+* Возможность декларативного определения графического интерфейса с помощью специального языка разметки **XAML**, основанном на **XML** и представляющем альтернативу программному созданию графики и элементов управления, а также возможность комбинировать **XAML** и **C#**
 
 * Независимость от разрешения экрана: поскольку в WPF/Avalonia все элементы измеряются в независимых от устройства единицах, приложения на WPF/Avalonia легко масштабируются под разные экраны с разным разрешением.
 
@@ -53,11 +51,11 @@
 
 * Богатые возможности по созданию различных приложений: это и мультимедиа, и двухмерная и трехмерная графика, и богатый набор встроенных элементов управления, а также возможность самим создавать новые элементы, создание анимаций, привязка данных, стили, шаблоны, темы и многое другое
 
-* Аппаратное ускорение графики - вне зависимости от того, работаете ли вы с 2D или 3D, графикой или текстом, все компоненты приложения транслируются в объекты, понятные Direct3D/OpenGL, и затем визуализируются с помощью процессора на видеокарте, что повышает производительность, делает графику более плавной.
+* Аппаратное ускорение графики - вне зависимости от того, работаете ли вы с **2D** или **3D**, графикой или текстом, все компоненты приложения транслируются в объекты, понятные **Direct3D/OpenGL**, и затем визуализируются с помощью процессора на видеокарте, что повышает производительность, делает графику более плавной.
 
 ## Установка Avalonia
 
-Далее мы будем использовать Avalonia, но так как он не входит в .NET, то нужно его установить:
+Avalonia мы использовать не будем, поэтому этот раздел можно пропустить
 
 1. В основном окне **Rider** выбрать вкладку *Configure -> Plugins*:
 
@@ -78,93 +76,116 @@
 
 ## Создание оконного приложения
 
+### Microsoft Visual Studio
+
+Создайте новый проект "Приложение WPF (Майкрософт)"
+
+![](../img/wpf_01.png)
+
+По-умолчанию IDE Visual Studio разбито на 3 части:
+
+![](../img/task013.png)
+
+* слева панель элементов - список визуальных элементов (кнопки, токстовые поля и т.п.)
+* в центре основное окно, предназначенное для редактирования исходного кода. При отображении файлов XAML (читается как "замл") разбито на две части: визуальное отображение и текст разметки
+* справа Обозреватель решений и структура проекта: Properties (Свойства); Ссылки (Зависимости); App.config - настройки проекта; App.xaml - разметка проекта и MainWindow.xaml - разметка окна.
+
+Если каких-то панелей нет на экране, то можно их найти в меню Вид.
+
+### Rider
+
 Запустите **Rider** и создайте новое решение:
 
 Если шаблоны установлены нормально, то в окне создания нового проекта появится секция *Other*:
 
 Выберите **Avalonia .NET Core App** 
 
+### Настройка проекта
+
 При создании задаете *Название решения*, *Имя проекта* и, если нужно, *Расположение*. Остальные параметры оставляем по-умолчанию.
 
 >Название проекта должно отражать предметную область или название компании (за это есть отдельные баллы на чемпионате и демо-экзамене)
 
 **Основные типы файлов проекта:**
 
-* **.AXAML** (Avalonia eXtended Application Markup Languale) - язык разметки, очень похож на XML. В таких файлах хранится описание внешнего вида окна. 
+* **XAML** eXtended Application Markup Languale - язык разметки, очень похож на XML. В таких файлах хранится описание внешнего вида окна.
 * **.cs** - файлы с исходным кодом на C# для окна.
 
 ## Структура проекта
 
-В структуре проекта следует выделить следующие моменты:
-
-**Во-первых**, в проекте имеется файл `App.axaml` и связанный с ним файл кода `App.axaml.cs` - это глобальные файлы для всего приложения, позже мы о них поговорим подробнее. А пока только следует знать, что в `App.axaml.cs` задается класс главного окна программы, которое будет открываться при запуске приложения. Если вы откроете этот файл, то можете найти в нем строку `desktop.MainWindow = new MainWindow();` - то есть в данном случае, когда мы запустим приложение, главным будет окно из класса `MainWindow`.
+В структуре проекта **WPF** следует выделить следующие моменты. **Во-первых**, в проекте имеется файл `App.xaml` и связанный с ним файл кода `App.xaml.cs` - это глобальные файлы для всего приложения, позже мы о них поговорим подробнее. А пока только следует знать, что `App.xaml` задает файл окна программы, которое будет открываться при запуске приложения. Если вы откроете этот файл, то можете найти в нем строку `StartupUri="MainWindow.xaml"` - то есть в данном случае, когда мы запустим приложение, будет создаваться интерфейс из файла `MainWindow.xaml`.
 
-Далее в структуре определены файл разметки `MainWindow.axaml` и файл связанного кода `MainWindow.axaml.cs`. Файл `MainWindow.axaml` и представляет определение окна приложения, которое мы увидим при запуске.
+Далее в структуре определены файл разметки `MainWindow.xaml` и файл связанного кода `MainWindow.xaml.cs`. Файл `MainWindow.xaml` и представляет определение окна приложение, которое мы увидим при запуске.
 
 ### Введение в язык XAML
 
-**AXAML (Avalonia eXtensible Application Markup Language)** - язык разметки, используемый для инициализации объектов в технологиях на платформе .NET. Применительно к **Avalonia** данный язык используется прежде всего для создания пользовательского интерфейса декларативным путем, наподобие HTML в веб-программировании.
+**XAML** (eXtensible Application Markup Language) - язык разметки, используемый для инициализации объектов в технологиях на платформе **.NET**. Применительно к **WPF** данный язык используется прежде всего для создания пользовательского интерфейса декларативным путем, наподобие **HTML** в веб-программировании.
 
-**AXAML** - не является обязательной частью приложения, мы вобще можем обходиться без него, создавая все элементы в файле связанного с ним кода на языке C#. Однако использование AXAML все-таки несет некоторые преимущества:
+**XAML** - не является обязательной частью приложения, мы вобще можем обходиться без него, создавая все элементы в файле связанного с ним кода на языке **C#**. Однако использование **XAML** все-таки несет некоторые преимущества:
 
 * Возможность отделить графический интерфейс от логики приложения, благодаря чему над разными частями приложения могут относительно автономно работать разные специалисты: над интерфейсом - дизайнеры, над кодом логики - программисты.
 
-* Компактность, понятность, код на AXAML относительно легко поддерживать.
+* Компактность, понятность, код на XAML относительно легко поддерживать.
 
-При компиляции приложения код в axaml-файлах также компилируется в бинарное представление кода axaml. И затем это бинарное представление встраивается в финальную сборку приложения - exe или dll-файл.
+При компиляции приложения в Visual Studio код в xaml-файлах также компилируется в бинарное представление кода xaml, которое называется BAML (Binary Application Markup Language). И затем код baml встраивается в финальную сборку приложения - exe или dll-файл.
 
 #### Структура и пространства имен AXAML
 
-При создании нового проекта он уже содержит файлы с кодом axaml. Так, создаваемый по умолчанию в проекте файл `MainWindow.axaml` будет иметь следующую разметку:
+При создании нового проекта **WPF** он уже содержит файлы с кодом xaml. Так, создаваемый по умолчанию в проекте файл `MainWindow.xaml` будет иметь следующую разметку:
 
 ```xml
 <Window 
-    xmlns="https://github.com/avaloniaui"
+    x:Class="XamlApp.MainWindow"
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
-    mc:Ignorable="d" 
-    d:DesignWidth="800" 
-    d:DesignHeight="450"
-    x:Class="AvaloniaFirst.MainWindow"
-    Title="AvaloniaFirst"
+    xmlns:local="clr-namespace:XamlApp"
+    mc:Ignorable="d"
+    Title="MainWindow" 
+    Height="350" 
+    Width="525"
 >
-    Welcome to Avalonia!
+    <Grid>
+         
+    </Grid>
 </Window>
 ```
 
-Если вы совершенно не знакомы с axaml и с xml, то даже этот небольшой минимальный код окна может вызывать затруднения.
+Если вы совершенно не знакомы с **xaml** и с **xml**, то даже этот небольшой минимальный код окна может вызывать затруднения.
 
-Подобно структуре веб-страничке на html, здесь есть некоторая иерархия элементов. Элементом верхнего уровня является тег **Window**, который представляет собой окно приложения. При создании других окон в приложении нам придется всегда начинать объявление интерфейса с элемента **Window**, поскольку это элемент самого верхнего уровня.
+Подобно структуре веб-страничке на **html**, здесь есть некоторая иерархия элементов. Элементом верхнего уровня является тег **Window**, который представляет собой окно приложения. При создании других окон в приложении нам придется всегда начинать объявление интерфейса с элемента **Window**, поскольку это элемент самого верхнего уровня.
 
 Кроме **Window** существует еще два элемента верхнего уровня:
 
 * Page
 * Application
 
-Элемент **Window** имеет вложенный текст (Welcome to Avalonia!), а также подобно html-элементам ряд атрибутов (*Title*, *DesignWidth*, *DesignHeight*) - они задают заголовок, ширину и высоту окна соответственно.
+Элемент **Window** имеет вложенный пустой элемент **Grid**, а также подобно html-элементам ряд атрибутов (_Title_, _Width_, _Height_) - они задают заголовок, ширину и высоту окна соответственно.
 
-#### Пространства имен AXAML
+#### Пространства имен XAML
 
-При создании кода на языке C#, чтобы нам были доступны определенные классы, мы подключаем пространства имен с помощью директивы using, например, `using Avalonia.Controls;`.
+При создании кода на языке **C#**, чтобы нам были доступны определенные классы, мы подключаем пространства имен с помощью директивы `using`, например, `using System.Windows;`.
 
-Чтобы задействовать элементы в AXAML, мы также подключаем пространства имен. Аттрибуты **xmlns** как раз и представляют собой пространства имен, подключаемые в проект.
+Чтобы задействовать элементы в **XAML**, мы также подключаем пространства имен. Вторая и третья строчки как раз и представляют собой пространства имен, подключаемые в проект по умолчанию. А атрибут _xmlns_ представляет специальный атрибут для определения пространства имен в **XML**.
 
-Так, пространство имен **https://github.com/avaloniaui** содержит описание и определение большинства элементов управления. Так как является пространством имен по умолчанию, то объявляется без всяких префиксов.
+Так, пространство имен `http://schemas.microsoft.com/winfx/2006/xaml/presentation` содержит описание и определение большинства элементов управления. Так как является пространством имен по умолчанию, то объявляется без всяких префиксов.
 
-**http://schemas.microsoft.com/winfx/2006/xaml** - это пространство имен, которое определяет некоторые свойства AXAML, например свойство _Name_ или _Key_. Используемый префикс `x` в определении `xmlns:x` означает, что те свойства элементов, которые заключены в этом пространстве имен, будут использоваться с префиксом x - `x:Name` или `x:Key`. Это же пространство имен используется уже в аттрибуте `x:Class="AvaloniaFirst.MainWindow"` - здесь создается ссылка на класс **MainWindow** и соответствующий ему файл кода, куда будет прописываться логика для данного окна приложения.
+`http://schemas.microsoft.com/winfx/2006/xaml` - это пространство имен, которое определяет некоторые свойства **XAML**, например свойство _Name_ или _Key_. Используемый префикс `x` в определении `xmlns:x` означает, что те свойства элементов, которые заключены в этом пространстве имен, будут использоваться с префиксом `x` - `x:Name` или `x:Key`. Это же пространство имен используется уже в первой строчке `x:Class="XamlApp.MainWindow"` - здесь создается новый класс **MainWindow** и соответствующий ему файл кода, куда будет прописываться логика для данного окна приложения.
 
 Это два основных пространства имен. Рассмотрим остальные:
 
-**xmlns:d="http://schemas.microsoft.com/expression/blend/2008"**: предоставляет поддержку атрибутов в режиме дизайнера. Это пространство имен преимущественно предназначено для другого инструмента по созданию дизайна на XAML - Microsoft Expression Blend
+`xmlns:d="http://schemas.microsoft.com/expression/blend/2008"`: предоставляет поддержку атрибутов в режиме дизайнера. Это пространство имен преимущественно предназначено для другого инструмента по созданию дизайна на XAML - Microsoft Expression Blend
 
-**xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"**: обеспечивает режим совместимости разметок XAML.
+`xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"`: обеспечивает режим совместимости разметок XAML. В определении объекта Window двумя строчками ниже можно найти его применение:
 
-Важно понимать, что эти пространства имен не эквивалентны тем пространствам имен, которые подключаются при помощи директивы **using** в c#. 
+`xmlns:local="clr-namespace:XamlApp"`: пространство имен текущего проекта. Так как в нашем случае проект называется **XamlApp**, то простраство имен называется аналогично. И через префикс `local` я смогу получить в XAML различные объекты, которые я определил в проекте.
+
+Важно понимать, что эти пространства имен не эквивалентны тем пространствам имен, которые подключаются при помощи директивы `using` в **c#**.
 
 #### Элементы и их атрибуты
 
-XAML предлагает очень простую и ясную схему определения различных элементов и их свойств. Каждый элемент, как и любой элемент XML, должен иметь открывающий и закрывающий теги, как в случае с элементом Window:
+XAML предлагает очень простую и ясную схему определения различных элементов и их свойств. Каждый элемент, как и любой элемент XML, должен иметь открывающий и закрывающий теги, как в случае с элементом `Window`:
 
 ```xml
 <Window></Window>
@@ -176,7 +197,7 @@ XAML предлагает очень простую и ясную схему о
 <Window />
 ```
 
-Но в отличие от элементов xml каждый элемент в XAML соответствует определенному классу C#. Например, элемент **Button** соответствует классу **Avalonia.Controls.Button**. А свойства этого класса соответствуют атрибутам элемента **Button**.
+Но в отличие от элементов xml каждый элемент в XAML соответствует определенному классу **C#**. Например, элемент `Button` соответствует классу `System.Windows.Controls.Button`. А свойства этого класса соответствуют атрибутам элемента `Button`.
 
 Например, добавим кнопку в создаваемую по умолчанию разметку окна:
 
@@ -249,30 +270,29 @@ XAML предлагает очень простую и ясную схему о
 
 ### Файлы отделённого кода
 
-При создании нового проекта в дополнение к создаваемому файлу `MainWindow.axaml` создается также файл отделённого кода `MainWindow.axaml.cs`, где, как предполагается, должна находится логика приложения связанная с разметкой из `MainWindow.axaml`. Файлы XAML позволяют нам определить интерфейс окна, но для создания логики приложения, например, для определения обработчиков событий элементов управления, нам все равно придется воспользоваться кодом C#.
+При создании нового проекта в дополнение к создаваемому файлу `MainWindow.xaml` создается также файл отделённого кода `MainWindow.xaml.cs`, где, как предполагается, должна находится логика приложения связанная с разметкой из `MainWindow.xaml`. Файлы XAML позволяют нам определить интерфейс окна, но для создания логики приложения, например, для определения обработчиков событий элементов управления, нам все равно придется воспользоваться кодом **C#**.
 
 По умолчанию в разметке окна используется атрибут `x:Class`:
 
 ```xml
 <Window 
-    x:Class="AvaloniaFirst.MainWindow" 
+    x:Class="XamlApp.MainWindow" 
     ...
 ```
 
-Атрибут `x:Class` указывает на класс, который будет представлять данное окно и в который будет компилироваться код в XAML при компиляции. То есть во время компиляции будет генерироваться класс **AvaloniaFirst.MainWindow**, унаследованный от класса **Avalonia.Controls**.
+Атрибут `x:Class` указывает на класс, который будет представлять данное окно и в который будет компилироваться код в XAML при компиляции. То есть во время компиляции будет генерироваться класс **XamlApp.MainWindow**, унаследованный от класса **System.Windows.Window**.
 
-Кроме того в файле отделенного кода `MainWindow.axaml.cs`, который **Rider** создает автоматически, мы также можем найти класс с тем же именем - в данном случае класс **MainWindow**. По умолчанию он имеет некоторый код:
+Кроме того в файле отделенного кода `MainWindow.xaml.cs`, который **Visual Studio** создает автоматически, мы также можем найти класс с тем же именем - в данном случае класс `XamlApp.MainWindow`. По умолчанию он имеет некоторый код:
 
 ```cs 
-using Avalonia.Controls;
-
-namespace AvaloniaFirst;
-
-public partial class MainWindow : Window
+namespace XamlApp
 {
-    public MainWindow()
+    public partial class MainWindow : Window
     {
-        InitializeComponent();
+        public MainWindow()
+        {
+            InitializeComponent();
+        }
     }
 }
 ```
@@ -285,14 +305,14 @@ public partial class MainWindow : Window
 
 В приложении часто требуется обратиться к какому-нибудь элементу управления. Для этого надо установить у элемента в XAML свойство **Name**.
 
-Еще одной точкой взаимодействия между xaml и C# являются события. С помощью атрибутов в XAML мы можем задать события, которые будут связанны с обработчиками в коде C#.
+Еще одной точкой взаимодействия между **xaml** и **C#** являются события. С помощью атрибутов в **XAML** мы можем задать события, которые будут связанны с обработчиками в коде **C#**.
 
 Итак, в разметке главного окна определим два элемента: кнопку и текстовое поле.
 
 >В теге **Window** может быть только один вложенный элемент. Обычно используют **Grid** (подробнее о нём поговорим ниже)
 
 ```xml
-<Grid>
+<Grid x:Name="grid1">
     <TextBox 
         x:Name="textBox1" 
         Width="150" 
@@ -304,43 +324,39 @@ public partial class MainWindow : Window
         Width="100" 
         Height="30" 
         Content="Кнопка" 
-        Click="Button1_OnClick" />
+        Click="Button_Click" />
 </Grid>
 ```
 
-И изменим класс **MainWindow** добавив в него обработчик нажатия кнопки *Button1_OnClick*:
+И изменим класс **MainWindow** добавив в него обработчик нажатия кнопки *Button_Click*:
 
 ```cs
-public partial class MainWindow : Window
+namespace XamlApp
 {
-    public MainWindow()
+    public partial class MainWindow : Window
     {
-        InitializeComponent();
-    }
-
-    private void Button1_OnClick(
-        object? sender, 
-        RoutedEventArgs e)
-    {
-        string text = textBox1.Text;
-        if (text != "")
+        public MainWindow()
+        {
+            InitializeComponent();
+        }
+ 
+        private void Button_Click(
+            object sender, 
+            RoutedEventArgs e)
         {
-            MessageBoxManager
-                .GetMessageBoxStandard(
-                    "Caption", 
-                    text,
-                    ButtonEnum.Ok)
-                .ShowAsync();
+            string text = textBox1.Text;
+            if (text != "")
+            {
+                MessageBox.Show(text);
+            }
         }
     }
 }
 ```
 
->В **Avalonia** нет встроенного класса **MessageBox**. Нужно через **NuGet** установить библиотеку `MessageBox.Avalonia`
-
 Определив имена элементов в XAML, затем мы можем к ним обращаться в коде c#: `var text = textBox1.Text`.
 
-В обработчике нажатия кнопки просто выводится сообщение, введенное в текстовое поле. После определения обработчика мы его можем связать с событием нажатия кнопки в xaml через атрибут _Click_: `Click="Button1_OnClick"`. В результате после нажатия на кнопку мы увидим в окне введенное в текстовое поле сообщение.
+В обработчике нажатия кнопки просто выводится сообщение, введенное в текстовое поле. После определения обработчика мы его можем связать с событием нажатия кнопки в xaml через атрибут _Click_: `Click="Button_Click"`. В результате после нажатия на кнопку мы увидим в окне введенное в текстовое поле сообщение.
 
 #### Пространства имен из C# в XAML
 
@@ -351,14 +367,12 @@ public partial class MainWindow : Window
 ```xml
 <Window
     ...
-    xmlns:local="clr-namespace:AvaloniaFirst"
+    xmlns:local="clr-namespace:XamlApp"
 ```
 
 Локальное пространство имен позволяет подключить все классы, которые определены в коде C# в нашем проекте. Например, добавим в проект следующий класс (напоминаю правило: каждый класс создаётся в отдельном файле):
 
 ```cs
-namespace AvaloniaFirst;
-
 public class Phone
 {
     public string Name { get; set; }
@@ -374,22 +388,27 @@ public class Phone
 Используем этот класс в коде xaml:
 
 ```xml
-<Button 
-    x:Name="phoneButton"  
-    Width="250" 
-    Height="40"
+<Grid x:Name="layoutGrid">
+    <Button 
+        x:Name="phoneButton" 
+        Width="250" 
+        Height="40" 
+        HorizontalAlignment="Center"
     >
-    <local:Phone
-        Name="Lumia 950" 
-        Price="700" />
-</Button>
+        <Button.Content>
+            <local:Phone
+                Name="Lumia 950" 
+                Price="700" />
+        </Button.Content>
+    </Button>
+</Grid>
 ```
 
 Так как пространство имен проекта проецируется на префикс `local`, то все классы проекта можно использовать в форме `local:Название_Класса`. Так в данном случае в качестве содержимого кнопки устанавливается объект **Phone**. 
 
-![](../img/rider14.png)
+![](../img/wpf_02.png)
 
-Для вывода содержимого любого объекта используется метод *ToString*. Этот метод объявлен в классе **Object** и по-умолчанию выводит просто название класса, в нашем случае **AvaloniaFirst.Phone**. Для того, чтобы получить нужную нам информацию об объекте необходимо переопределить метод *ToString*.
+Для вывода содержимого любого объекта используется метод *ToString*. Этот метод объявлен в классе **Object** и по-умолчанию выводит просто название класса. Для того, чтобы получить нужную нам информацию об объекте необходимо переопределить метод *ToString*.
 
 Мы можем подключить любые другие пространства имен, классы которых мы хотим использовать в приложении. Например:
 
@@ -803,10 +822,14 @@ xmlns:sys="clr-namespace:System;assembly=mscorlib"
 
 ![](../img/08012.png)
 
-## Image. Ресурсы
+## Image
 
 Для добавления ресурсов в проект можно создать в нём каталог (кликнуть правой кнопкой мышки на название проекта и выбрать *Добавить - Создать папку*) и скопировать в него нужный ресурс, в нашем случае картинку.
 
+>Обратите внимание, копировать нужно именно в интерфейсе Visual Studio, а не средствами ОС, иначе VS будет искать ресурс не в папке проекта, а в текущей папке VS.
+
+![](../img/task020.png)
+
 И добавим картинку в сетку:
 
 ```xml
@@ -815,35 +838,16 @@ xmlns:sys="clr-namespace:System;assembly=mscorlib"
         <ColumnDefinition Width="100"/>
         <ColumnDefinition/>
     </Grid.ColumnDefinitions>
-    <StackPanel 
-        Orientation="Vertical"
-        VerticalAlignment="Bottom" 
-    >
-        <Image 
-            Source="img/latte-800x800.jpeg"/>
-    </StackPanel>
-</Grid>
-```
-
-Если попытаться запустить проект, то Avalonia выдаст ошибку "Не найден ресурс".
-
-Для того, чтобы добавить картинку в ресурс есть два варианта:
-
-1. В контекстном меню файла картинки в дереве проекта выбрать пункт **Properties** и в поле **Build action** выбрать `AvaloniaResource`
-
-1. Если в проекте много картинок, то проще добавить весь каталог с картинками в ресурсы. Для этого в файл проекта (в режиме просмотра файловой системы открыть файл `<Название проекта>.csproj`)  и в тег **ItemGroup** добавить запись
 
-    ```xml
-    <ItemGroup>
-        <AvaloniaResource Include="img\**"/>
-    </ItemGroup>
-    ```
+    <Image 
+        Source="img/latte-800x800.jpeg"/>
 
-    ![](../img/rider19.png)
+</Grid>
+```
 
-Атрибут **VerticalAlignment** устанавливает вертикальное выравнивание.
+Атрибут _VerticalAlignment_ устанавливает вертикальное выравнивание элемента относительно предка (Grid-а).
 
-Атрибут **Grid.ColumnSpan** (есть и **RowSpan**) позволяет разместить элемент не в одной ячейке Grid-a, а "размазать" на несколько. Например, можно сделать фоновую картинку (как в примере ниже) или горизонтальное меню в верхней строке.
+Атрибут _Grid.ColumnSpan_ (есть и _RowSpan_) позволяет разместить элемент не в одной ячейке Grid-a, а "размазать" на несколько. Например, можно сделать фоновую картинку (как в примере ниже) или горизонтальное меню в верхней строке.
 
 ```xml
 <Image 
@@ -858,9 +862,9 @@ xmlns:sys="clr-namespace:System;assembly=mscorlib"
 
 Реализовать все примеры из лекции. В репозиторий добавить скриншоты результатов работы.
 
-Напоминаю, что для добавления в **MarkDown** картинок используется синтаксис: `![](путь/имя картинки)`
+Напоминаю, что для добавления в **MarkDown** картинок используется синтаксис: `![alt-строка](./относительный путь/имя картинки)`
 
-Использовать относительные пути и соблюдать регистр символов (у вас на Windows разницы не будет, но на сервере Linux и имена файлов регистрзависимые).
+Использовать относительные пути и соблюдать регистр символов (у вас на Windows разницы не будет, но на git-сервере Linux и имена файлов регистрзависимые).
 
 Например:
 
@@ -870,6 +874,15 @@ xmlns:sys="clr-namespace:System;assembly=mscorlib"
 
 ---
 
+## Контрольные вопросы
+
+1. Технологии создания оконных приложений
+1. Особенности WPF
+1. Компоновка
+1. Grid
+1. StackPanel
+1. WrapPanel
+
 Предыдущая лекция | &nbsp; | Следующая лекция
 :----------------:|:----------:|:----------------:
 [Библиотеки классов](./t7_dll.md) | [Содержание](../readme.md#тема-8-оконные-приложения) | [Ресурсы](./wpf_resource.md)

+ 35 - 15
articles/wpf_resource.md

@@ -1,13 +1,13 @@
 Предыдущая лекция | &nbsp; | Следующая лекция
 :----------------:|:----------:|:----------------:
-[Обзор типов оконных приложений в C#. Знакомство со структурой проекта WPF/Avalonia. Компоновка. Image. Ресурсы.](./t8_win_app.md) | [Содержание](../readme.md#тема-8-оконные-приложения) | [Привязка (Binding). Интерфейс INotifyPropertyChanged. Форматирование значений привязки и конвертеры значений.](./t8_binding.md)
+[Обзор типов оконных приложений в C#. Знакомство со структурой проекта WPF/Avalonia. Компоновка. Image.](./t8_win_app.md) | [Содержание](../readme.md#тема-8-оконные-приложения) | [Привязка (Binding). Интерфейс INotifyPropertyChanged. Форматирование значений привязки и конвертеры значений.](./t8_binding.md)
 
 
 # Ресурсы
 
 ## Концепция ресурсов в WPF
 
-В WPF важное место занимают **ресурсы**. В данном случае под ресурсами подразумеваются не дополнительные файлы (или **физические ресурсы**), как, например, аудиофайлы, файлы с изображениями, которые добавляются в проект. Здесь речь идет о **логических ресурсах**, которые могут представлять различные объекты - элементы управления, кисти, коллекции объектов и т.д. Логические ресурсы можно установить в коде XAML или в коде C# с помощью свойства Resources. Данное свойство опредлено в базовом классе **FrameworkElement**, поэтому его имеют большинство классов WPF.
+В WPF важное место занимают **ресурсы**. В данном случае под ресурсами подразумеваются не дополнительные файлы (или **физические ресурсы**), как, например, аудиофайлы, файлы с изображениями, которые добавляются в проект. Здесь речь идет о **логических ресурсах**, которые могут представлять различные объекты - элементы управления, кисти, коллекции объектов и т.д. Логические ресурсы можно установить в коде **XAML** или в коде **C#** с помощью свойства _Resources_. Данное свойство опредлено в базовом классе **FrameworkElement**, поэтому его имеют большинство классов **WPF**.
 
 В чем смысл использования ресурсов? Они повышают эффективность: мы можем определить один раз какой-либо ресурс и затем многократно использовать его в различных местах приложения. В связи с этим улучшается поддержка - если возникнет необходимость изменить ресурс, достаточно это сделать в одном месте, и изменения произойдут глобально в приложении.
 
@@ -81,7 +81,7 @@ button1.Background = (Brush)this.TryFindResource("buttonGradientBrush");
 //button1.Background = (Brush)this.Resources["buttonGradientBrush"];
 ```
 
-С помощью свойства _Add()_ объект кисти и его произвольный ключ добавляются в словарь. Далее с помощью метода _TryFindResource()_ мы пытаемся найти ресурс в словаре и установить его в качестве фона. Причем, так как этот метод возвращает object, необходимо выполнить приведение типов.
+С помощью метода _Add()_ объект кисти и его произвольный ключ добавляются в словарь. Далее с помощью метода _TryFindResource()_ мы пытаемся найти ресурс в словаре и установить его в качестве фона. Причем, так как этот метод возвращает object, необходимо выполнить приведение типов.
 
 Всего у **ResourceDictionary** можно выделить следующие методы и свойства:
 
@@ -248,13 +248,23 @@ private void Button_Click(object sender, RoutedEventArgs e)
 
 ### Установка динамических ресурсов в коде C#
 
-Ранее мы рассмотрели, как устанавливать в коде C# статические ресурсы:
+Ранее мы рассмотрели, как устанавливать в коде **C#** статические ресурсы:
 
 ```cs
-LinearGradientBrush gradientBrush = new LinearGradientBrush();
-gradientBrush.GradientStops.Add(new GradientStop(Colors.LightGray, 0));
-gradientBrush.GradientStops.Add(new GradientStop(Colors.White, 1));
-this.Resources.Add("buttonGradientBrush", gradientBrush);
+var gradientBrush = new LinearGradientBrush();
+
+gradientBrush
+    .GradientStops
+    .Add(new GradientStop(
+        Colors.LightGray, 0));
+
+gradientBrush
+    .GradientStops
+    .Add(new GradientStop(
+        Colors.White, 1));
+
+this.Resources
+    .Add("buttonGradientBrush", gradientBrush);
  
 button1.Background = (Brush)this.TryFindResource("buttonGradientBrush");
 ```
@@ -262,15 +272,25 @@ button1.Background = (Brush)this.TryFindResource("buttonGradientBrush");
 Установка динамического ресурса призводится немного иначе:
 
 ```cs
-LinearGradientBrush gradientBrush = new LinearGradientBrush();
-gradientBrush.GradientStops.Add(new GradientStop(Colors.LightGray, 0));
-gradientBrush.GradientStops.Add(new GradientStop(Colors.White, 1));
-this.Resources.Add("buttonGradientBrush", gradientBrush);
+var gradientBrush = new LinearGradientBrush();
+
+gradientBrush
+    .GradientStops
+    .Add(new GradientStop(
+        Colors.LightGray, 0));
+
+gradientBrush
+    .GradientStops
+    .Add(new GradientStop(
+        Colors.White, 1));
+
+this.Resources
+    .Add("buttonGradientBrush", gradientBrush);
  
 button1.SetResourceReference(Button.BackgroundProperty, "buttonGradientBrush");
 ```
 
-Для установки применяется метод **SetResourceReference()**, который есть у большинства элементов WPF. Первым параметром в него передается свойство зависимости объекта, для которого предназначен ресурс, а вторым - ключ ресурса. Общая форма установки:
+Для установки применяется метод **SetResourceReference()**, который есть у большинства элементов **WPF**. Первым параметром в него передается свойство зависимости объекта, для которого предназначен ресурс, а вторым - ключ ресурса. Общая форма установки:
 
 ```
 объект.SetResourceReference(Класс_объекта.Свойство_КлассаProperty, ключ_ресурса);
@@ -278,7 +298,7 @@ button1.SetResourceReference(Button.BackgroundProperty, "buttonGradientBrush");
 
 ### Элементы StaticResource и DynamicResource
 
-В ряде случае в разметке XAML бывает удобнее использовать не расширения разметки тип `"{StaticResource}"`, а полноценные элементы **DynamicResource** и **StaticResource**. Например:
+В ряде случае в разметке **XAML** бывает удобнее использовать не расширения разметки тип `"{StaticResource}"`, а полноценные элементы **DynamicResource** и **StaticResource**. Например:
 
 ```xml
 <Window ...>
@@ -451,4 +471,4 @@ button1.SetResourceReference(Button.BackgroundProperty, "buttonGradientBrush");
 
 Предыдущая лекция | &nbsp; | Следующая лекция
 :----------------:|:----------:|:----------------:
-[Обзор типов оконных приложений в C#. Знакомство со структурой проекта WPF/Avalonia. Компоновка. Image. Ресурсы.](./t8_win_app.md) | [Содержание](../readme.md#тема-8-оконные-приложения) | [Привязка (Binding). Интерфейс INotifyPropertyChanged. Форматирование значений привязки и конвертеры значений.](./t8_binding.md)
+[Обзор типов оконных приложений в C#. Знакомство со структурой проекта WPF/Avalonia. Компоновка. Image.](./t8_win_app.md) | [Содержание](../readme.md#тема-8-оконные-приложения) | [Привязка (Binding). Интерфейс INotifyPropertyChanged. Форматирование значений привязки и конвертеры значений.](./t8_binding.md)

TEMPAT SAMPAH
img/task013.png


TEMPAT SAMPAH
img/wpf_01.png


TEMPAT SAMPAH
img/wpf_02.png


+ 13 - 1
readme.md

@@ -226,7 +226,9 @@
 
 ## Тема 8. Оконные приложения.
 
-1. [Обзор типов оконных приложений в C#. Знакомство со структурой проекта WPF/Avalonia. Компоновка. Image. Ресурсы.](./articles/t8_win_app.md)
+### Теория
+
+1. [Обзор типов оконных приложений в C#. Знакомство со структурой проекта WPF/Avalonia. Компоновка. Image.](./articles/t8_win_app.md)
 1. [Ресурсы](./articles/wpf_resource.md)
 1. [Привязка (Binding). Интерфейс INotifyPropertyChanged. Форматирование значений привязки и конвертеры значений.](./articles/t8_binding.md)
 1. [Элементы управления. Обзор.](./articles/t8_elements.md)
@@ -249,6 +251,16 @@
 1. [Поиск/сортировка](./articles/lab_wpf_search_sort.md)
 1. Создание WPF-приложений по индивидуальным заданиям (подготовка к экзамену)
 
+### Контрольные вопросы
+
+1. Технологии создания оконных приложений
+1. Особенности WPF
+1. Компоновка
+1. Grid
+1. StackPanel
+1. WrapPanel
+
+
 ## [ЭКЗАМЕН](./articles/exam.md)
 
 <!--