При выполнении в лабораторной работе упражнения №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
Вкладка Page7. Присвоение свойству DataContext логической ссылки на ресурс
Вернемся к примеру вкладки Page2 и немного изменим его.
- В панели Solution Explorer для папки Images вызовите контекстное меню и скопируйте в нее командой Add/Existing Item из прилагаемого каталога Source файл wood.jpg
-
Выделите файл wood.jpg и в панели Properties проверьте его настройки в оболочке. Они должны быть такими
- Build Action=None
- Copy to Output Directory=Copy if newer
- В файле Window1.xaml.cs в класс Pictures добавьте новый код
class Pictures { // Поле public static ImageBrush picture = new ImageBrush(); public static ImageBrush picture1 = new ImageBrush(); static Pictures() { picture.ImageSource = new BitmapImage( new Uri(@"Images\flower2.jpg", UriKind.Relative)); picture.Stretch = Stretch.UniformToFill; picture.Opacity = 1.0D; picture1.ImageSource = new BitmapImage( new Uri(@"Images\wood.jpg", UriKind.Relative)); picture1.Stretch = Stretch.Uniform; picture1.Opacity = 1.0D; } // Свойство public static ImageBrush Picture { get { return picture; } } public static ImageBrush Picture1 { get { return picture1; } } }
- В коллекцию ресурсов разметки окна Window1 добавьте новый ресурс
<Window.Resources> <SolidColorBrush x:Key="ControlColorBrush" Color="{x:Static SystemColors.ControlColor}" /> <local:Pictures x:Key="wood" /> </Window.Resources>
Вспомним, что при разработке вкладки Page2 мы уже добавили в заголовок дескриптора Window запись
xmlns:local="clr-namespace:ElementWithObject"
импортирования пространства имен приложения для доступа к свойству класса Pictures из разметки и теперь просто используем готовый псевдоним local.
-
В контейнер TabControl добавьте новую вкладку Page7 со следующей разметкой
<!-- Page7. Присвоение свойству DataContext логической ссылки на ресурс --> <TabItem Header="Page7" DataContext=" {StaticResource ResourceKey=wood}"> <Button Background="{Binding Path=Picture1, Mode=OneWay}" /> </TabItem>
Синтаксический анализатор ищет ресурс вначале в элементе его использования со свойством DataContext, а затем вверх по логическому дереву, поэтому мы расположили определение ресурса в словаре окна. То же самое присходит и с DataContext. Когда в выражении привязки атрибут Source пропущен, то WPF ищет определение источника в атрибуте DataContext вначале в элементе с выражением привязки и далее в родительских элементах, поэтому мы расположили DataContext в элементе <TabItem>.
-
Запустите приложение - результат вкладки Page7 выглядет так
Вкладка Page8. Управление свойством DataContext в процедурном коде
Обычно DataContext задается в коде. В частности, эта методика применяется к объектам ADO.NET, которые необходимо инициировать в коде и нельзя заполнять декларативно. Пока что без объектов ADO.NET рассмотрим этот способ. Естественно, что элемент, в котором будет задаваться свойство DataContext, должен иметь имя для возможности обращения из процедурного кода.
-
Добавьте в контейнер TabControl файла Window1.xaml новую вкладку с именем Page8
<!-- Page8. Управление свойством DataContext в процедурном коде --> <TabItem Header="Page8"> <StackPanel Name="stackPanel8"> <TextBlock FontSize="16" TextDecorations="Underline" TextAlignment="Center" Margin="0,5,0,15" Foreground="Red" Text="Управление DataContext в коде" /> <StackPanel Orientation="Horizontal" Margin="5"> <Label Width="40" Content="{Binding Path=Value, Mode=OneWay}" /> <Slider Name="slider8" Width="230" Minimum="11" Maximum="54" TickFrequency="2" TickPlacement="BottomRight" IsSnapToTickEnabled="True" /> </StackPanel> <Button Margin="5" Content="Подключить источник в DataContext" Click="button8_Click"> </Button> <TextBlock Margin="0,10" Foreground="Blue" FontSize="{Binding Path=Value, Mode=OneWay}" Text="Simple Text" /> </StackPanel> </TabItem>
-
Расширьте класс Window1 следующим процедурным кодом
public partial class Window1 : Window { public Window1() { InitializeComponent(); } bool bindingFlag = false; private void button8_Click(object sender, RoutedEventArgs e) { Button button = (Button)sender; if (bindingFlag == false) { stackPanel8.DataContext = slider8; button.Content = "Отключить источник в DataContext"; } else { stackPanel8.DataContext = null; button.Content = "Подключить источник в DataContext"; } bindingFlag = !bindingFlag; } }
-
Запустите приложение и испытайте работу вкладки Page8, внешний вид которой будет таким
Вкладка Page9. Создание и привязка пользовательского объекта
Мы можем создать пользовательский элемент управления и привязать его в коде или разметке. Приведем пример из Петцольда (стр. 633) и создадим простой пользовательский объект со свойством зависимости.
-
Добавьте в пространство имен ElementWithObject текущего проекта в файле Window1.xaml.cs новый класс SimpleElement
// Простой пользовательский элемент управления class SimpleElement : FrameworkElement { // Статическое поле зависимости, базовое для свойства public static DependencyProperty NumberProperty; // Инициализация поля в статическом конструкторе static SimpleElement() { NumberProperty = DependencyProperty.Register( "Number", typeof(double), typeof(SimpleElement), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsRender)); } // Свойство зависимости для доступа к полю public double Number { get { return (double)this.GetValue(NumberProperty); } set { this.SetValue(NumberProperty, value); } } // Жесткое кодирование размера области вывода protected override Size MeasureOverride(Size availableSize) { return new Size(200, 20); } // Вывод значения свойства Number protected override void OnRender(DrawingContext drawingContext) { drawingContext.DrawRectangle(Brushes.Yellow, new Pen(Brushes.Red, 1.0), new Rect(new Size(200, 20))); drawingContext.DrawText( new FormattedText( Convert.ToInt32(Number).ToString(), System.Globalization.CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface("Arial"), 16.0D, SystemColors.WindowTextBrush), new Point(0, 0)); } }
При регистрации поля зависимости используется перечисление FrameworkPropertyMetadataOptions, которое определяет типы поведения свойства зависимости.
-
Добавьте в контейнер TabControl файла Window1.xaml новую вкладку с именем Page9, которую заполните так
<!-- Привязка пользовательского элемента управления --> <TabItem Header="Page9"> <StackPanel> <ScrollBar Orientation="Horizontal" Margin="24" Maximum="100" LargeChange="10" SmallChange="1" Value="{Binding ElementName=simple9, Path=Number, Mode=OneWayToSource}" /> <local:SimpleElement x:Name="simple9" HorizontalAlignment="Center" /> <ScrollBar Name="scroll9" Orientation="Horizontal" Margin="24" Maximum="100" LargeChange="10" SmallChange="1" Value="{Binding ElementName=simple9, Path=Number, Mode=TwoWay}" /> <local:SimpleElement HorizontalAlignment="Center" Number="{Binding ElementName=scroll9, Path=Value, Mode=OneWay}" /> </StackPanel> </TabItem>
Здесь мы тоже просто используем ранее определенный псевдоним local импортирования пространства имен приложения для доступа к классу SimpleElement из разметки.
Разметка вводит в контейнер <StackPanel> две пары элементов: "библиотечный элемент прокрутки" - "пользовательский элемент". В секции определения первого пользовательского элемента вводится его имя в пространство имен XAML: x:Name="simple9", которое в дальнейшем используется в выражениях привязки другими элементами как имя объекта-источника. Применение обычного атрибута Name="simple9" будет считаться ошибкой.
Первый объект ScrollBar определяет одностороннюю привязку типа OneWayToSource со свойством Number пользовательского элемента и успешно обновляет это свойство при перемещении бегунка. Второй элемент ScrollBar определяет двухстороннюю привязку к свойству Number и успешно обновляет его в представлении двух пользовательских элементов, а также обновляется сам при изменении этого свойства. Однако перемещение второго бегунка хоть и изменяет свойство Number пользовательского элемента, но не влияет на состояние первого бегунка, поскольку определенная в первом ScrollBar привязка OneWayToSource обеспечивает передачу информации только в одну сторону.
-
Запустите приложение и убедитесь в сказанном (слава Петцольду!)
Привязка к источнику с помощью свойства RelativeSource
Класс System.Windows.Data. RelativeSource в выражении привязки целевого элемента указывает источник, которым является родительский объект, находящийся на расстоянии неопределенного (или определенного) числа шагов вверх по дереву элементов в направлении к корню. Этот объект также можно использовать и для привязки элемента к самому себе.
ип такой привязки задается свойством Mode из перечисления RelativeSourceMode, возможные значения которого следующие (Ancestor - предок)
Значение | Описание |
---|---|
FindAncestor | Ссылается на источник с данными в визуальном дереве, который находится на неопределенное число шагов выше целевого элемента, содержащего выражение привязки. При использовании этого режима необходимо задавать дополнительные уточнения в свойствах класса RelativeSource, таких как AncestorType и AncestorLevel. Свойство AncestorType указывает тип источника привязки. Свойство AncestorLevel определяет, с какого вышестоящего уровня от приемника начинать поиск источника. Значение AncestorLevel=1 указывает ближайший к приемнику уровень начального поиска исходного объекта привязки |
PreviousData | Когда ссылки на источники данных перечислены в списке, этот режим позволяет сменить текущий источник на предыдущий в списке |
Self | Действует внутри элемента, содержащего выражение привязки, и позволяет сменить одно привязанное свойство на другое в том же элементе, т.е. привязать объект к самому себе |
TemplatedParent | Если целевой элемент с выражением привязки находится внутри шаблона, такой режим привязывает его к данным шаблона |
На первый взгляд привязка со свойством RelativeSource кажется излишним усложнением. Ведь к источнику можно привязаться обычными средствами с помощью ElementName или Source. Однако такое возможно не всегда, в частности, при использовании шаблонов может выручить только привязка со свойством RelativeSource. Механизм шаблонов в этой теме не рассматривается, а вот применение данной привязки в традиционных задачах мы продемонстрируем на нескольких примерах.
Исполнение привязки со свойством RelativeSource, как и обычной, тоже возможно в двух синтаксисах: по синтаксису элементов свойств и по синтаксису расширения разметки.