При выполнении в лабораторной работе упражнения №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
Вкладка Page10. Привязка RelativeSource к свойствам родительского элемента
-
Добавьте в контейнер TabControl файла Window1.xaml новую вкладку с именем Page10, которую заполните так
<!-- Относительная привязка RelativeSource к источнику --> <TabItem Header="Page10"> <StackPanel> <Grid Tag="Привязка к Grid по синтаксису элементов свойств"> <Button Margin="5" FontSize="10"> <Button.Content> <Binding Path="Tag" Mode="OneWay"> <Binding.RelativeSource> <RelativeSource Mode="FindAncestor" AncestorType="Grid" AncestorLevel="1" /> </Binding.RelativeSource> </Binding> </Button.Content> </Button> </Grid> <Grid Tag="Привязка к Grid по синтаксису расширения разметки"> <Button Margin="5" FontSize="10" Content="{Binding Path=Tag, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Grid, AncestorLevel=1}, Mode=OneWay}" /> </Grid> <!-- Привязка к свойству заголовка окна по синтаксису элементов свойств --> <TextBlock TextAlignment="Center"> <TextBlock.Text> <Binding Path="Title" Mode="OneWay"> <Binding.RelativeSource> <RelativeSource Mode="FindAncestor" AncestorType="Window" /> </Binding.RelativeSource> </Binding> </TextBlock.Text> </TextBlock> <Label HorizontalAlignment="Center"> <Label.Content> <Binding Path="Title" Mode="OneWay"> <Binding.RelativeSource> <RelativeSource Mode="FindAncestor" AncestorType="{x:Type Window}"> </RelativeSource> </Binding.RelativeSource> </Binding> </Label.Content> </Label> <!-- Привязка к свойству заголовка окна по синтаксису расширения разметки --> <TextBlock TextAlignment="Center" Text="{Binding Path=Title, RelativeSource= {RelativeSource FindAncestor, AncestorType={x:Type Window}}, Mode=OneWay}" /> <Label HorizontalAlignment="Center" Content="{Binding Path=Title, RelativeSource= {RelativeSource Mode=FindAncestor, AncestorType=Window}, Mode=OneWay}" /> </StackPanel> <TabItem>
Свойство Content первых двух кнопок мы привязали к свойству Tag родительского элемента Grid. Остальные 4 элемента привязаны к свойству Title окна. Свойство AncestorLevel по умолчанию равно 1, поэтому там, где не требуется явно задать иное значение, его можно опустить. В синтаксисе расширения разметки атрибут Mode=FindAncestor можно писать без параметра Mode.
-
Запустите приложение - вкладка Page10 будет выглядеть так
Вкладка Page11. Привязка RelativeSource к вложенным свойствам
Приведем пример, в котором привязка выполняется к свойству родителя, вложенному в него из другого объекта.
-
Добавьте в контейнер TabControl файла Window1.xaml новую вкладку с именем Page11, которую заполните так
<!-- Относительная привязка RelativeSource --> <TabItem Header="Page11" Selector.IsSelected="True"> <DockPanel LastChildFill="True"> <StackPanel DockPanel.Dock="Top"> <TextBlock FontSize="16" TextAlignment="Center" Margin="0,5,0,5"> <TextBlock.Foreground> <SolidColorBrush Color="Purple" /> </TextBlock.Foreground> Привязка с помощью RelativeSource </TextBlock> <ListBox Foreground="Red" SelectionMode="Multiple" Height="60"> <CheckBox Selector.IsSelected="False" IsChecked="{Binding RelativeSource={RelativeSource Mode=Self}, Path=(Selector.IsSelected), Mode=TwoWay}" Foreground="{Binding Path=Foreground, RelativeSource= {RelativeSource Mode=FindAncestor, AncestorType=ListBox}, Mode=OneWay}"> 1) Это еще флажок, элемент списка правее </CheckBox> <CheckBox ListBox.IsSelected="False" IsChecked="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=1, AncestorType={x:Type ListBoxItem}}, Path=IsSelected, Mode=TwoWay}" Foreground="{Binding Path=Foreground, RelativeSource= {RelativeSource Mode=FindAncestor, AncestorType=ListBox}, Mode=OneWay}"> 2) Это еще флажок, элемент списка правее </CheckBox> <CheckBox Foreground="{Binding Path=Foreground, RelativeSource= {RelativeSource FindAncestor, AncestorType=ListBox}, Mode=OneWay}"> 3) Это еще флажок, элемент списка правее </CheckBox> <ListBoxItem IsSelected="False"> <CheckBox IsChecked="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}, Path=IsSelected, Mode=TwoWay}" Foreground="{Binding Path=Foreground, RelativeSource= {RelativeSource FindAncestor, AncestorType=ListBox}, Mode=OneWay}"> 4) Это еще флажок, элемент списка правее </CheckBox> </ListBoxItem> </ListBox> </StackPanel> <RichTextBox Margin="0,5,0,0" ScrollViewer.VerticalScrollBarVisibility="Auto"> </RichTextBox> </DockPanel> </TabItem>
Поскольку вкладка <TabItem> может содержать только один элемент, мы упаковали ее содержимое в компоновочную панель <DockPanel>. В качестве содержимого контейнера <DockPanel> определили два элемента: компоновочную панель <StackPanel> и контейнер <RichTextBox>, где чуть позже разместим краткую инструкцию пользователя (для тренировки). Настройка <StackPanel DockPanel.Dock="Top"> приклеивает эту панель к верхней части родителя <DockPanel>, а настройка <DockPanel LastChildFill="True"> заставляет элемент <RichTextBox> занять всю остальную оставшуся свободной часть.
На первом месте в контейнере <StackPanel> размещен элемент <TextBlock> для вывода заголовка. Далее следует элемент списка <ListBox>, который в качестве своих дочерних объектов содержит элементы флажков <CheckBox>. Интересно то, что первые три элемента списка не указаны явно и только последний элемент указан.
Если не создавать контейнер элемента ListBoxItem явно, то WPF сама создает его неявно и присваивает его свойству IsSelected значение Selector.IsSelected. Только один раз в момент создания свойство Selector.IsSelected считывается привязанными элементами. Но далее при изменении выбора элемента это свойство не обновляется. Чтобы показать, что Selector.IsSelected действительно не обновляется, свойство IsChecked первого флажка связывается с Selector.IsSelected первого элемента ListBoxItem в соответствии с режимом RelativeSource Mode=Self.
Когда пользователь меняет выделение первого элемента ListBoxItem, элемент CheckBox остается в прежнем состоянии. И наоборот, установка или снятие флажка в первом CheckBox не влияет на смену выделения родителя ListBoxItem. Обратите внимание, что в выражении привязки первого CheckBox значение привязываемого вложенного свойства заключается в круглые скобки.
Итак, когда контейнер элемента не создается явно, следует использовать вложенное свойство зависимостей Selector.IsSelected для начального выделения элемента в Selector. Объекты TabItem, ListBox и ComboBox являются контейнерами для списковых элементов управления и наследуют от Selector. Поэтому, когда их дочерние элементы заданы явно, то каждый имеет свое свойство IsSelected. К этому свойству мы и привязываемся во втором и четвертом элементах списка, что дает взаимную синхронизацию выделения флажка и элемента списка.
-
Запустите приложение - пока вкладка Page11 может выглядеть так
Замечание. Если из заголовка вкладки
<TabItem Header="Page11" Selector.IsSelected="True">удалить атрибут Selector.IsSelected="True", то синхронная работа второго элемента нарушается (не знаю, почему...).
Свойство Foreground каждого элемента списка, заданного явно или неявно, мы связали с одноименным свойством контейнера <ListBox>, в котором задали ему значение Red для обеспечения контраста надписи на выделенном элементе (и для тренировки). Эту привязку мы тоже выполнили по рассматриваемой технологии RelativeSource.
Последним в компоновочном контейнере <DockPanel> мы забронировали элемент <RichTextBox>, который обеспечивает поддержку документов нефиксированного формата <FlowDocument>. Наша задача - создать краткую инструкцию 'чего-то... чего-то', разместить ее во внешнем файле как элемент <FlowDocument> и загрузить в контейнер <RichTextBox> во время выполнения. К теме привязки этот кусочек задачи отношения не имеет, но для тренировки, чтобы заполнить оставшееся на вкладке (и в голове) вакантное место, решим ее.
Там шпионки с крепким телом,
Ты их в дверь - они в окно!
Говори, что с 'этим делом'
Мы покончили давно!
(В.С. Высоцкий)
-
Добавьте к текущему проекту командой Project/Add New Item новый XAML -файл с именем Instruct.xaml (не забудьте изменить расширение файла c xml на xaml )
-
Выделите в Solution Explorer новый файл Instruct.xaml и измените через панель Properties его свойства на
- Build Action = None
- Copy to Output Directory=Copy if newer
-
Удалите в файле Instruct.xaml сгенерированное мастером содержимое и заполните его следующей разметкой (чем бы то нибыло, абы-кабы, аты-баты и т.д.)
<FlowDocument FontSize="11" Background="White" > <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>
-
Запустите приложение - компилятор (синтаксический анализатор) начинает ругаться, что не понимает конструкцию файла и не может преобразовать ее в объектный код. Текстовый редактор оболочки тоже зашелся в истерике, потому что не видит библиотеку WPF
-
Добавьте в открывающий дескриптор <FlowDocument> подключение пространства имен WPF -библиотеки
<FlowDocument FontSize="11" Background="White" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" > ............................................. </FlowDocument>;
Откомпилируйте решение командой Build/Build Solution - вроде бы все успокоилось
Если бы мы поместили содержимое файла Instruct.xaml сразу внутрь контейнера <RichTextBox>...</RichTextBox>, то в дескрипторе окна <Window> уже есть такое подключение и ничего специального предпринимать бы не пришлось. И все бы сразу заработало, можете так и попробовать. Но чтобы не захломлять разметку вкладки Page11, мы пошли окружным путем и решили вынести документ в отдельный файл Instruct.xaml. В наказание за инициативу нам еще нужно будет этот файл подключить к контейнеру <RichTextBox>. Сделать это можно в процедурном коде или в разметке - через словарь ресурсов. Применим поочередно оба способа.
Подключение документа через процедурный код
-
Дополните в разметке вкладки Page11 контейнер <RichTextBox> именем и зарегистрируйте обработчик события Loaded так
<RichTextBox Name="documentReader" Loaded="documentReader_Loaded" Margin="0,5,0,0" ScrollViewer.VerticalScrollBarVisibility="Auto"> </RichTextBox>
-
В разметке на записи регистрации обработчика события Loaded контейнера <RichTextBox> вызовите контекстное меню и командой Navigate to Event Handler создайте в файле Window1.xaml.cs заготовку этого обработчика, которую заполните следующим кодом
private void documentReader_Loaded(object sender, RoutedEventArgs e) { String fileName = "Instruct.xaml"; FileStream xamlFile = new FileStream(fileName, FileMode.Open, FileAccess.Read); FlowDocument content = XamlReader.Load(xamlFile) as FlowDocument; documentReader.Document = content; xamlFile.Close(); }
-
В начало файла Window1.xaml.cs добавьте подключение пространств имен для используемых в обработчике классов и перечислений
using System; using System.Collections.Generic; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; // Дополнительные пространства имен using System.Windows.Markup;// Для класса XamlReader using System.IO; // Для класса FileStream, // перечислений FileMode и FileAccess namespace ElementWithObject { public partial class Window1 : Window { .................................................... } }
-
Запустите приложение с вкладкой Page11 - все работает как надо и снимок экрана может быть таким