При выполнении в лабораторной работе упражнения №1 , а именно при выполнении нижеследующего кода: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using Microsoft.Xna.Framework.Graphics;
namespace Application1 { public partial class MainForm : Form { // Объявим поле графического устройства для видимости в методах GraphicsDevice device;
public MainForm() { InitializeComponent();
// Подпишемся на событие Load формы this.Load += new EventHandler(MainForm_Load);
// Попишемся на событие FormClosed формы this.FormClosed += new FormClosedEventHandler(MainForm_FormClosed); }
void MainForm_FormClosed(object sender, FormClosedEventArgs e) { // Удаляем (освобождаем) устройство device.Dispose(); // На всякий случай присваиваем ссылке на устройство значение null device = null; }
void MainForm_Load(object sender, EventArgs e) { // Создаем объект представления для настройки графического устройства PresentationParameters presentParams = new PresentationParameters(); // Настраиваем объект представления через его свойства presentParams.IsFullScreen = false; // Включаем оконный режим presentParams.BackBufferCount = 1; // Включаем задний буфер // для двойной буферизации // Переключение переднего и заднего буферов // должно осуществляться с максимальной эффективностью presentParams.SwapEffect = SwapEffect.Discard; // Устанавливаем размеры заднего буфера по клиентской области окна формы presentParams.BackBufferWidth = this.ClientSize.Width; presentParams.BackBufferHeight = this.ClientSize.Height;
// Создадим графическое устройство с заданными настройками device = new GraphicsDevice(GraphicsAdapter.DefaultAdapter, DeviceType.Hardware, this.Handle, presentParams); }
protected override void OnPaint(PaintEventArgs e) { device.Clear(Microsoft.Xna.Framework.Graphics.Color.CornflowerBlue);
base.OnPaint(e); } } } Выбрасывается исключение: Невозможно загрузить файл или сборку "Microsoft.Xna.Framework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d" или один из зависимых от них компонентов. Не удается найти указанный файл. Делаю все пунктуально. В чем может быть проблема? |
Основы привязки данных в WPF
Подключение документа через ресурс
Теперь ту же задачу подключения документа к контейнеру <RichTextBox> быстренько повторим с использованием механизма ресурсов, чтобы вспомнить молодость. При этом нам не придется писать ни строчки процедурного кода, все выполним в разметке. Чтобы не вмешиваться в процедурный код, просто удалим регистрацию обработчика события Loaded из разметки элемента RichTextBox. Пусть обработчик существует как обычный незадействованный метод класса Window1 и никуда не встревает со своими услугами. А компилятор тоже будет молчать.
Было |
<RichTextBox Name="documentReader" Loaded="documentReader_Loaded" Margin="0,5,0,0" ScrollViewer.VerticalScrollBarVisibility="Auto"> </RichTextBox> |
---|---|
Стало |
<RichTextBox Name="documentReader" Margin="0,5,0,0" ScrollViewer.VerticalScrollBarVisibility="Auto"> </RichTextBox> |
Имя удалять не будем, потому что на него ссылается код обработчика. Если хотим убрать и имя, тогда нужно очистить или вообще удалить обработчик documentReader_Loaded() из класса Window1 (кому как, а лично мне это делать жалко, код-то вымучен бессонными ночами и недопитыми литрами. Хотя с допитыми может быть получилось бы лучше).
-
В панели Solution Explorer выделите корневой узел текущего проекта и через меню оболочки командой Project/Add Resource Dictionary добавьте новый файл с именем по умолчанию Dictionary1.xaml
-
Выделите в Solution Explore новый файл Dictionary1.xaml и проверьте через панель Properties его свойства, чтобы они были такими
- Build Action = Page
- Copy to Output Directory=Do not copy
-
Скопируйте из файла Instruct.xaml в новый файл Dictionary1.xaml все содержимое с разметкой документа <FlowDocument> и обязательно добавьте в его открывающем дескрипторе ключ ресурса x:Key="instruct". При этом можете удалить, а можете и оставить, индивидуальное подключение пространств имен XAML, которое в дескрипторе ресурса уже присутствует (можете удалить любое из них или ничего не удалять)
Файл Dictionary1.xaml должен стать таким (текст неважен, важна разметка)
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" > <FlowDocument x:Key="instruct" FontSize="11" Background="White" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" > <List MarkerStyle="Decimal"> <ListItem> <Paragraph> Первый флажок двунаправленно привязан булевым свойством IsChecked к вложенному логическому свойству Selector.IsSelected, которое инициализируется один раз и больше не меняется. Поэтому флажок и элемент списка меняются независимо. Режим поиска родителя определен значением Mode=Self - искать источник в том же элементе. </Paragraph> </ListItem> <ListItem> <Paragraph> Второй флажок своим свойством IsChecked привязан двунаправленной привязкой к свойству IsSelected своего ближайшего контейнера, которым является элемент списка ListBoxItem, поэтому и меняется синхронно с ним, обеспечивая нормальную логику работы списка. Режим поиска родителя определен значением Mode=FindAncestor - искать источник в ближайшем родителе. </Paragraph> </ListItem> <ListItem> <Paragraph> В третьем элементе списка флажок и элемент списка ListBoxItem никак не связаны, поэтому изменяются автономно как в первом элементе, где связь хоть и установлена, но источник Selector.IsSelected остается постоянным </Paragraph> </ListItem> <ListItem> <Paragraph> Четвертый элемент списка задается явно и флажок своим свойством IsChecked привязан двунаправленной привязкой к свойству IsSelected этого контейнера. Поэтому флажок и элемент списка работают синхронно, как и в случае со вторым списком. </Paragraph> </ListItem> </List> </FlowDocument> </ResourceDictionary>
-
Дополните разметку элемента RichTextBox во вкладке Page11 следующей конструкцией подключения ресурса по синтаксису элемента свойства
<RichTextBox Name="documentReader" Margin="0,5,0,0" ScrollViewer.VerticalScrollBarVisibility="Auto"> <RichTextBox.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="Dictionary1.xaml" /> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </RichTextBox.Resources> <RichTextBox.Document> <StaticResource ResourceKey="instruct" /> </RichTextBox.Document> </RichTextBox>
-
Запустите приложение - вкладка Page11 должна выглядеть точно так, как и в предыдущем случае подключения документа через процедурный код
Обращает на себя внимание применение элементов ListBox (ListBoxItem и List (ListItem). Оба называются списками. Но первый из них относится к элементам управления, поскольку служит для отображения информации и обеспечивает взаимодействие с пользователем. А второй - просто к элементам (хотя это и более общая категория), поскольку незримо участвует только в верстке документа. Да ладно, в конце-концов, - это касается только терминологии. Главное - не как называть, а правильно понимать и применять.
Вкладка Page12. Привязка RelativeSource в процедурном коде
Возьмем за основу привязку RelativeSource в разметке, а потом перенесем ее в процедурный код.
-
Добавьте в контейнер TabControl файла Window1.xaml новую вкладку с именем Page12, которую заполните следующей начальной разметкой, использующей привязку RelativeSource
<!-- Привязка RelativeSource в коде --< <TabItem Header="Page12"< <!-- Привязка Button.Content к StackPanel уровней 1 и 2 --< <StackPanel Tag="Эта информация находится в StackPanel уровня 2"< <StackPanel Tag="Эта информация находится в StackPanel уровня 1"< <Button Margin="5" Content="{Binding Path=Tag, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=StackPanel, AncestorLevel=1}, Mode=OneWay}" /< <Button Margin="5" Content="{Binding Path=Tag, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=StackPanel, AncestorLevel=2}, Mode=OneWay}" /< </StackPanel< <!-- Привязка TextBlock.Text к Window.Title --< <Label< Следующая информация находится в Window: </Label< <TextBlock Margin="5,0"< <TextBlock.Text< <Binding Path="Title" Mode="OneWay"< <Binding.RelativeSource< <RelativeSource Mode="FindAncestor" AncestorType="Window" /< </Binding.RelativeSource< </Binding< </TextBlock.Text< </TextBlock< </StackPanel< </TabItem<
-
Запустите приложение - вывод вкладки Page12 будет таким
-
Удалите привязку RelativeSource из элементов вкладки Page12 и присвойте привязываемым источникам имена для возможности адресации из процедурного кода
Окончательный вид вкладки Page12 будет таким
<!-- Привязка RelativeSource в коде --> <TabItem Header="Page12" Selector.IsSelected="True"> <!-- Привязка Button.Content к StackPanel уровней 1 и 2 --> <StackPanel Tag="Эта информация находится в StackPanel уровня 2"> <StackPanel Tag="Эта информация находится в StackPanel уровня 1"> <Button Margin="5" Name="button12level1" /> <Button Margin="5" Name="button12level2" /> </StackPanel> <!-- Привязка TextBlock.Text к Window.Title --> <Label> Следующая информация находится в Window: </Label> <TextBlock Margin="5,0" Name="textBlock12" /> </StackPanel> </TabItem>
-
Добавьте в конструктор класса Window1 файла Window1.xaml.cs следующий процедурный код привязки RelativeSource
public Window1() { InitializeComponent(); //******************************************************** // Привязка RelativeSource для элементов вкладки Page12 //******************************************************** // // button12level1 // Binding binding = new Binding(); binding.Path = new PropertyPath("Tag"); binding.Mode = BindingMode.OneWay; binding.RelativeSource = new RelativeSource( RelativeSourceMode.FindAncestor, typeof(StackPanel), 1); BindingOperations.SetBinding(button12level1, Button.ContentProperty, binding); // // button12level2 // binding = new Binding("Tag"); binding.Mode = BindingMode.OneWay; binding.RelativeSource = new RelativeSource( RelativeSourceMode.FindAncestor, typeof(StackPanel), 2); BindingOperations.SetBinding(button12level2, Button.ContentProperty, binding); // // textBlock12 // binding = new Binding(); binding.Path = new PropertyPath("Title"); binding.Mode = BindingMode.OneWay; binding.RelativeSource = new RelativeSource( RelativeSourceMode.FindAncestor, typeof(Window), 1); BindingOperations.SetBinding(textBlock12, TextBlock.TextProperty, binding); }
-
Запустите приложение - вывод вкладки Page12 остался в точности таким, как и с привязкой в разметк
Пока об основах привязки поговорили достаточно. Но это еще далеко не все. В следующих разделах мы рассмотрим вопросы более серьезного применения привязки: привязки WPF к объектам ADO.NET, привязки в шаблонах и т.д.