Все необходимые для выполнения данной работы программы можно найти в прилагаемом каталоге.
При изучении любого средства программирования используют примеры, которые иллюстрируют применение этого средства. Различают примеры двух видов:
В наших упражнениях рассматриваются преимущественно примеры технологий.
Текст и рисунки - главные информационные составляющие любого приложения. WPF имеет все стандартные элементы, необходимые для работы с текстом. Для простых случаев используются упрощенные элементы представления текста
Label - меткаTextBlock - текстовый блокTextBox - текстовое полеPasswordBox - поле пароляДля более сложных случаев используются высокоразвитые элементы работы с документами. WPF разделяет текстовые документы на две основные категории на основе их предполагаемого использования:
Документы фиксированного формата предназначены для приложений,
требующих точного представления в режиме WYSIWYG (режим точного отображения
- 'что вижу то и имею'), независимо от используемого дисплея или принтера.
Документы фиксированного формата обычно используются при подготовке публикаций
с помощью настольных издательских средств, обработке текста и разметке формы,
где строгое соблюдение исходного дизайна страницы является обязательным. Содержимое
документов фиксированного формата поддерживается классом FixedDocument, а для
просмотра используется класс DocumentViewer.
Документы фиксированного формата, как часть макета, поддерживает точное позиционирование содержимого элементов, независимо от используемых устройств отображения или печати. Например, страница формата фиксированного документа, просматриваемая на экране с разрешением 96 точек на дюйм, будет отображаться точно так же на выводе лазерного принтера с разрешением 600 точек на дюйм или устройстве фотовывода с разрешением 4800 точек на дюйм. Макет страницы остается неизменным во всех случаях, в то время как качество документа повышается в соответствии с возможностями каждого устройства.
Документы нефиксированного формата предназначены для оптимизации просмотра и удобочитаемости и наиболее удобны в использовании, когда простота чтения является основным требованием сценария документа. Вместо предварительно определенного макета, документы нефиксированного формата динамически изменяют и переформатируют свое содержимое на основе переменных времени выполнения, таких как размер окна и разрешение устройства, и дополнительных пользовательских настроек.
В зависимости от среды выполнения, документы нефиксированного формата оптимизируют просмотр и чтение для пользователя. Например, один тот же документ нефиксированного формата будет динамически переформатирован для оптимальной удобочитаемости как на 19-дюймовом экране с высоким разрешением, так и на небольшом 2x3-дюймовом экране карманного ПК. Кроме того, документы нефиксированного формата имеют множество встроенных возможностей, включая поиск, просмотр режимов оптимизации удобочитаемости и возможность изменения размера и вида шрифтов.
Документы нефиксированного формата представлены классом содержимого FlowDocument.
Этот класс обеспечивает размещение и форматирование содержимого потока с такими
дополнительными свойствами документов, как разбивка на страницы и столбцы.
Для отображения, редактирования и навигации по документу используются
классы-контейнеры
RichTextBox - текстовое поле с расширенными возможностямиFlowDocumentScrollViewer - текстовый блок с расширенным содержимым
и управляемой полосой прокруткиFlowDocumentPageViewer - дает возможность просматривать документ постранично
и имеет привычные навигационные элементыFlowDocumentReader - элемент управления, в котором пользователь сам вибирает
способ просмотра документа: одностраничный, многостраничный или с прокруткойЛюбой из этих классов может иметь только один элемент содержимого FlowDocument, который адресуется их свойством Document. Если содержимое не
загружено в контейнер отображения, то свойство Document имеет значение null.
В данной лабораторной работе рассматриваются средства WPF для представления текста нефиксированного формата.
Текстовые элементы Label, TextBlock, TextBox, PasswordBox обычно
используются для создания небольшого текста в интерфейсе пользователя. Они
обладают достаточными для этого возможностями. Но отображать большие потоки
текста они непредназначены.
Создайте решение WpfApp с
проектом WpfText1 и назначьте его стартовым
Добавьте к проекту
новый файл с именем FontPropertyLists.cs 
Заполните файл FontPropertyLists.cs следующим кодомusing System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Media;
namespace WpfText1
{
/// <summary>
/// Код класса из примера MSDN
/// </summary>
public class FontPropertyLists
{
static Collection<FontFamily> fontFaces;
static Collection<FontStyle> fontStyles;
static Collection<FontWeight> fontWeights;
static Collection<double> fontSizes;
static int maxFontSizes = 36;
/// <summary>
/// Заполняет коллекцию доступных системе FontFamily
/// </summary>
public static ICollection<FontFamily> FontFaces
{
get
{
if (fontFaces == null) fontFaces = new Collection<FontFamily>();
foreach (FontFamily fontFamily in Fonts.SystemFontFamilies)
{
fontFaces.Add(fontFamily);
}
return fontFaces;
}
}
/// <summary>
/// Заполняет коллекцию доступных FontStyles
/// </summary>
public static ICollection FontStyles
{
get
{
if (fontStyles == null)
{
fontStyles = new Collection<FontStyle>();
fontStyles.Add(System.Windows.FontStyles.Normal);
fontStyles.Add(System.Windows.FontStyles.Oblique);
fontStyles.Add(System.Windows.FontStyles.Italic);
}
return fontStyles;
}
}
/// <summary>
/// Заполняет коллекцию доступных FontWeight
/// </summary>
public static ICollection FontWeights
{
get
{
if (fontWeights == null)
{
fontWeights = new Collection<FontWeight>();
Unique(System.Windows.FontWeights.Thin);
Unique(System.Windows.FontWeights.Light);
Unique(System.Windows.FontWeights.Regular);
Unique(System.Windows.FontWeights.Normal);
Unique(System.Windows.FontWeights.Medium);
Unique(System.Windows.FontWeights.Heavy);
Unique(System.Windows.FontWeights.SemiBold);
Unique(System.Windows.FontWeights.DemiBold);
Unique(System.Windows.FontWeights.Bold);
Unique(System.Windows.FontWeights.Black);
Unique(System.Windows.FontWeights.ExtraLight);
Unique(System.Windows.FontWeights.ExtraBold);
Unique(System.Windows.FontWeights.ExtraBlack);
Unique(System.Windows.FontWeights.UltraLight);
Unique(System.Windows.FontWeights.UltraBold);
Unique(System.Windows.FontWeights.UltraBlack);
}
return fontWeights;
}
}
static void Unique(FontWeight fontWeight)
{
if (fontWeights.IndexOf(fontWeight) == -1)
fontWeights.Add(fontWeight);
}
/// <summary>
/// Заполняет коллекцию доступных FontSizes
/// </summary>
public static Collection<double> FontSizes
{
get
{
if (fontSizes == null)
{
fontSizes = new Collection<double>();
for (double i = 8; i <= maxFontSizes; i++) fontSizes.Add(i);
}
return fontSizes;
}
}
// Методы для преобразования из TypeName в Type
public static bool CanParseFontStyle(string fontStyleName)
{
try
{
FontStyleConverter converter = new FontStyleConverter();
converter.ConvertFromString(fontStyleName);
return true;
}
catch
{
return false;
}
}
public static FontStyle ParseFontStyle(string fontStyleName)
{
FontStyleConverter converter = new FontStyleConverter();
return (FontStyle)converter.ConvertFromString(fontStyleName);
}
public static bool CanParseFontWeight(string fontWeightName)
{
try
{
FontWeightConverter converter = new FontWeightConverter();
converter.ConvertFromString(fontWeightName);
return true;
}
catch
{
return false;
}
}
public static FontWeight ParseFontWeight(string fontWeightName)
{
FontWeightConverter converter = new FontWeightConverter();
return (FontWeight)converter.ConvertFromString(fontWeightName);
}
}
}
Заполните файл Window1.xaml следующей разметкой<Window x:Class="WpfText1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1"
Background="LightGray"
Height="300"
Width="300"
MinHeight="300"
MinWidth="300"
ResizeMode="CanResizeWithGrip"
WindowStartupLocation="CenterScreen"
FocusManager.FocusedElement="{Binding ElementName='fontSizeListBox'}"
>
<TabControl>
<!--Вкладка Label-->
<TabItem Header="Label">
<!--Сетка 4x3-->
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="60" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<!--Пропорции ширины столбцов-->
<ColumnDefinition Width="2.7*" />
<ColumnDefinition Width="1.3*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Border
Grid.Row="0" Grid.ColumnSpan="3"
BorderThickness="3"
BorderBrush="Violet"
>
<Label
VerticalContentAlignment="Center"
HorizontalContentAlignment="Center"
Foreground="Red"
FontWeight="{Binding ElementName=fontWeightListBox, Path=SelectedItem}"
FontSize="{Binding ElementName=fontSizeListBox, Path=SelectedItem}"
FontFamily="{Binding ElementName=fontFamilyListBox, Path=SelectedItem}"
Content="Элемент Label"
/>
</Border>
<Label
Grid.Row="1" Grid.Column="0"
HorizontalContentAlignment="Center"
Content="FontFamily:"
/>
<TextBox
Grid.Row="2" Grid.Column="0"
Name="fontFamilyTextBox"
Text="{Binding ElementName=fontFamilyListBox, Path=SelectedItem}"
TextChanged="fontFamilyTextBox_TextChanged"
/>
<ListBox
Grid.Row="3" Grid.Column="0"
Name="fontFamilyListBox" SelectedIndex="0"
/>
<Label
Grid.Row="1" Grid.Column="1"
HorizontalContentAlignment="Center"
Content="FontWeight:"
/>
<TextBox
Grid.Row="2" Grid.Column="1"
Name="fontWeightTextBox"
Text="{Binding ElementName=fontWeightListBox, Path=SelectedItem}"
TextChanged="fontWeightTextBox_TextChanged"
/>
<ListBox
Grid.Row="3" Grid.Column="1"
Name="fontWeightListBox" SelectedIndex="0"
/>
<Label
Grid.Row="1" Grid.Column="2"
HorizontalContentAlignment="Center"
Content="FontSize:"
/>
<TextBox
Grid.Row="2" Grid.Column="2"
Name="fontSizeTextBox"
Text="{Binding ElementName=fontSizeListBox, Path=SelectedItem}"
TextChanged="fontSizeTextBox_TextChanged"
/>
<ListBox
Grid.Row="3" Grid.Column="2"
Name="fontSizeListBox" SelectedIndex="0"
/>
</Grid>
</TabItem>
</TabControl>
</Window>
Зарегистрированные
в элементах TextBox обработчики событий TextChanged заполните в файле Window1.xaml.csusing 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;
namespace WpfText1
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
// Заполняем коллекции и подключаем их к спискам ListBox
this.fontFamilyListBox.ItemsSource = FontPropertyLists.FontFaces;
this.fontWeightListBox.ItemsSource = FontPropertyLists.FontWeights;
this.fontSizeListBox.ItemsSource = FontPropertyLists.FontSizes;
// Выполняется после XAML
this.fontSizeListBox.SelectedIndex = this.fontSizeListBox.Items.Count - 1;
this.fontSizeListBox.ScrollIntoView(this.fontSizeListBox.Items.Count - 1);
}
// Сокрытие унаследованных от Window одноименных свойств
new public FontFamily FontFamily
{
get { return (FontFamily)this.fontFamilyListBox.SelectedItem; }
set
{
this.fontFamilyListBox.SelectedItem = value; // Выделить
this.fontFamilyListBox.ScrollIntoView(value); // Прокрутить до видимого
}
}
new public FontWeight FontWeight
{
get { return (FontWeight)this.fontWeightListBox.SelectedItem; }
set
{
this.fontWeightListBox.SelectedItem = value; // Выделить
this.fontWeightListBox.ScrollIntoView(value); // Прокрутить до видимого
}
}
new public double FontSize
{
get { return (double)this.fontSizeListBox.SelectedItem; }
set
{
this.fontSizeListBox.SelectedItem = value; // Выделить
this.fontSizeListBox.ScrollIntoView(value); // Прокрутить до видимого
}
}
private void fontFamilyTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
// Привести ListBox в соответствие с содержимым TextBox
this.FontFamily = new FontFamily(this.fontFamilyTextBox.Text);
}
private void fontWeightTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
// Привести ListBox в соответствие с содержимым TextBox
if (FontPropertyLists.CanParseFontWeight(this.fontWeightTextBox.Text))
{
this.FontWeight = FontPropertyLists.ParseFontWeight(this.fontWeightTextBox.Text);
}
}
private void fontSizeTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
// Привести ListBox в соответствие с содержимым TextBox
double fontSize;
if (double.TryParse(this.fontSizeTextBox.Text, out fontSize))
{
this.FontSize = fontSize; // В поле действительно число
}
}
}
}
Запустите проект -
получим инструмент для просмотра основных атрибутов библиотечного текстового
элемента Label
Обратите внимание,
как компоновка окна сохраняется при изменении его размеров и что окно имеет
минимальный размер. Разберитесь с кодом разметки и процедурным кодом C#Текстовый элемент TextBlock поддерживает способы программирования Windows и стили Web. Он обладает развитыми средствами анимации и динамического программирования
стилей. Настройки элемента можно задавать в декларативном ( XAML ) и процедурном
( C# ) режимах. Проиллюстрируем некоторые возможности элемента TextBlock на примере.
Добавьте в файл Window1.xaml проекта WpfText1 вкладку TextBlock1 со следующей разметкой<!--Вкладка TextBlock1-->
<TabItem Header="TextBlock1">
<Border Background="Black">
<Border Margin="25" CornerRadius="50" BorderThickness="2" BorderBrush="Yellow">
<!--Радиальный градиент заливки Border-->
<Border.Background>
<RadialGradientBrush>
<GradientStop Color="Blue" Offset="0.1" />
<!--Непрозрачный alfa-канал и 000000 (Black)-->
<GradientStop Color="#FF000000" Offset="1.2" />
</RadialGradientBrush>
</Border.Background>
<!--Анимация градиентной подсветки внешнего контура Border-->
<Border.BitmapEffect>
<OuterGlowBitmapEffect x:Name="glow" GlowColor="Yellow" GlowSize="0" />
</Border.BitmapEffect>
<Border.Triggers>
<EventTrigger RoutedEvent="Border.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="glow"
Storyboard.TargetProperty="GlowSize"
From="30" To="0" Duration="0:0:1"
AutoReverse="True"
RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Border.Triggers>
<!--Текстовый блок-->
<TextBlock Name="text"
Text=""
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="White" FontSize="16"
Initialized="text_Initialized"
>
<TextBlock.Inlines>
<Bold>Это текстовый</Bold>
<LineBreak />
<Italic>элемент TextBlock</Italic>
<LineBreak />
<Run FontWeight="Bold" Foreground="Red">
Очень
</Run>
<Run FontStyle="Italic" TextDecorations="Underline" Foreground="Yellow">
красивый
</Run>
</TextBlock.Inlines>
<!--Действия в TextBlock-->
<TextBlock.LayoutTransform>
<RotateTransform x:Name="rotateTransform" Angle="0" />
</TextBlock.LayoutTransform>
<TextBlock.Triggers>
<!--Анимация поворота-->
<EventTrigger RoutedEvent="TextBlock.MouseDown">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="rotateTransform"
Storyboard.TargetProperty="Angle"
From="0" To="360" Duration="0:0:3"
RepeatBehavior="2x"
/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<!--Анимация изменения размера при заходе мыши-->
<EventTrigger RoutedEvent="TextBlock.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="text"
Storyboard.TargetProperty="FontSize"
To="26" Duration="0:0:0.2"
/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<!--Анимация изменения размера при сходе мыши-->
<EventTrigger RoutedEvent="TextBlock.MouseLeave">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="text"
Storyboard.TargetProperty="FontSize"
Duration="0:0:1"
/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</TextBlock.Triggers>
</TextBlock>
</Border>
</Border>
</TabItem>
Добавьте в процедурную
часть (файл Window1.xaml.cs ) код обработчика события Initialized элемента TextBlock, который в динамическом режиме дополняет декларативную настройку
этого текстового элементаprivate void text_Initialized(object sender, EventArgs e)
{
// Добавляем в TextBlock строку
Run run = new Run("\nDynamic");
run.FontFamily = new FontFamily("Curlz MT");
text.Inlines.Add(run);
run = new Run("Text");
run.FontFamily = new FontFamily("Comic Sans MS");
run.Foreground = Brushes.Aqua;
text.Inlines.Add(new Bold(run));
}
Запустите проект -
получим анимационный текст с персональными настройками стилей
Изучите приведенный
кодТекст в элементе TextBlock можно закрашивать произвольным рисунком.
В панели Solution
Explorer создайте
для корня дерева проекта папку Images и добавьте в нее (командой Add ) из
прилагаемого к работе каталога Source файлы Image1.jpg и Image2.png
Добавьте в файл Window1.xaml новую вкладку со следующей разметкой<!--Вкладка TextBlock2-->
<TabItem Header="TextBlock2">
<Canvas Background="Black">
<TextBlock
Canvas.Left = "10"
Canvas.Top="10"
FontFamily="Arial"
FontSize="36"
Foreground="Red"
Text="SolidColorBrush"
/>
<TextBlock
Canvas.Left = "10"
Canvas.Top="50"
FontFamily="Arial"
FontSize="75"
Text="Image1">
<TextBlock.Foreground>
<ImageBrush ImageSource="Images\Image1.jpg" Opacity=".9" />
</TextBlock.Foreground>
</TextBlock>
<TextBlock
Canvas.Left = "10"
Canvas.Top="130"
FontFamily="Arial"
FontSize="75"
Text="Image2">
<TextBlock.Foreground>
<ImageBrush ImageSource="Images/Image2.png" />
</TextBlock.Foreground>
</TextBlock>
</Canvas>
</TabItem>
Запустите приложение
- должно получиться следующее
Изучите приведенный
кодЕсли явно определить ширину элемента TextBlock и задать атрибут TextWraping="Wrap",
то блочный текст будет автоматически размещаться внутри заданной ширины.
Добавьте в файл Window1.xaml новую вкладку со следующей разметкой<!--Вкладка TextBlock3-->
<!-- Элемент TextBlock с переносом строк -->
<TabItem Header="TextBlock3">
<Grid Background="White">
<TextBlock
TextWrapping="Wrap"
FontSize="18"
TextAlignment="Center" >
Если в элементе TextBlock задать атрибут TextWraping="Wrap",
то блочный текст будет автоматически размещаться внутри
заданной ширины
<LineBreak />
<Run Foreground="Red" FontSize="28" FontFamily="Monotype Corsiva">
Панель Grid здесь введена для создания белого фона
</Run>
<LineBreak />
<Run FontSize="12">
Общие настройки родителя действуют на потомков до тех пор,
пока не будут переопределены внутри самих потомков
</Run>
</TextBlock>
</Grid>
</TabItem>
Запустите приложение
- должно получиться следующее
Изучите приведенный
кодИногда нет уверенности в том, что на компьютере пользователя есть нужные шрифты, с использованием которых программист разрабатывает интерфейс. В таком случае шрифты можно поставлять вместе с приложением.
Перейдите в раздел "Панель
управления", откройте папку " Шрифты " и перетащите мышью шрифт,
например, "Source )
В панели Solution
Explorer создайте в корне проекта папку Fonts, выделите ее и добавьте командой Project/Add Existing Item файл шрифта MTCORSVA.TTF
Добавьте в файл Window1.xaml новую вкладку со следующей разметкой<!--Вкладка TextBlock4-->
<!-- Элемент TextBlock с дополнительным шрифтом -->
<TabItem Header="TextBlock4">
<Grid Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock
FontFamily="Fonts/MTCORSVA.TTF#Monotype Corsiva"
FontSize="20"
TextWrapping="Wrap"
TextAlignment="Justify"
Margin="10"
ToolTip="Элемент TextBlock с дополнительным шрифтом">
Шрифт для этого текста подключен явно и поставляется
вместе с приложением на тот случай, если у бедного
пользователя компьютер окажется еще беднее.
</TextBlock>
<TextBlock Grid.Row="1" Margin="10" TextWrapping="Wrap">
В этом блоке текста используется шрифт по умолчанию и
нет всплывающей подсказки ToolTip, а в верхнем блоке есть
</TextBlock>
</Grid>
</TabItem>
Запустите приложение
- должно получиться следующее
Изучите приведенный
код
Добавьте к проекту
следующую вкладку со скриптовым кодом<!--TextBox и PasswordBox-->
<TabItem Header="TextBox" Selector.IsSelected="True">
<StackPanel VerticalAlignment="Center" Margin="10">
<TextBlock HorizontalAlignment="Center">
<Run FontSize="14" FontWeight="Bold">
Элементы PasswordBox и TextBox
</Run>
</TextBlock>
<Grid Height="20" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="Поле PasswordBox: " VerticalAlignment="Center" />
<PasswordBox Grid.Column="1" Name="passwordBox" />
</Grid>
<Grid Height="20" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="Поле TextBox: " VerticalAlignment="Center" />
<TextBox Grid.Column="1" Name="textBox"></TextBox>
</Grid>
<Grid Height="20" />
<Grid HorizontalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="5" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Content="Показать" Click="Button_Click" />
<ToggleButton Grid.Column="2" Name="toggleButton" Content="EnabledPassword"
Checked="toggleButton_Checked" Unchecked="toggleButton_Checked"/>
</Grid>
</StackPanel>
</TabItem>
Выделенную в разметке
кнопок регистрацию обработчиков наберите вручную
Добавьте в кодовую
часть следующие обработчикиprivate void Button_Click(object sender, RoutedEventArgs e)
{
textBox.Text = passwordBox.Password;
}
bool flagState = true;
Brush color;
private void toggleButton_Checked(object sender, RoutedEventArgs e)
{
// Сохраняем первоначальный цвет кнопки
if (flagState)
{
color = toggleButton.Background;
flagState = false;
}
if (toggleButton.IsChecked == true)
{
passwordBox.IsEnabled = false;
toggleButton.Background = Brushes.Red;
}
else
{
passwordBox.IsEnabled = true;
toggleButton.Background = color;
}
}
Запустите приложение,
поизменяйте размер окна и разберитесь с кодомРезультат будет таким

Классы-упаковки содержимого нефиксированного формата
FlowDocumentReaderRichTextBox FlowDocumentScrollViewer FlowDocumentPageViewer имеют дочерний элемент FlowDocument. В свою очередь, FlowDocument задает строгую
модель содержимого для своего дочернего содержимого. Дочерние элементы верхнего
уровня, содержащиеся в FlowDocument, должны быть производными от Block и называются блочными. Допустимыми дочерними элементами верхнего уровня в FlowDocument являются
следующие блоки:
| Блок | Описание |
|---|---|
Paragraph |
Содержит текст, возможно форматированный. |
List |
Содержит списки разного типа (нумерованный, маркированный и т. д.). |
Table |
Содержит таблицы, похожие на таблицы Microsoft Word или HTML. |
BlockUIContainer |
Содержит различные элементы пользовательского интерфейса, становящиеся частью размещения. |
Section |
Содержит группу прочих блоков. Разделы удобны для применения общих атрибутов к группам блоков, например, одни и те же атрибуты шрифта для нескольких абзацев. |
Внутри блоков дополнительное форматирование текста обеспечивается элементами, которые называются внутристрочными элементами. К ним относятся
BoldItalicLineBreakListListItemParagraphRunSectionSpanUnderlineВнутристрочные элементы могут быть вложенными друг в друга внутри блока или вместе с родительским блоком вложены в другой блок.
Некоторые элементы могут дополнительно настраиваться, например, такими атрибутами, как
BreakPageBefore=True" - начать с новой страницыFontSize="24" - размер шрифтаTypography .Variants="Superscript " - надстрочныйTypography .Variants="Subscript" - подстрочныйTextIndent="25" - отступ первой строки блокаTextIndent="-15" - выступ первой строки блокаMargin="20,0,0,0" - TextAlignment="Center" - текст посредине контейнера
рендеринга (представления)MarkerStyle="None" - тип маркера в элементе List Создание экземпляра класса FlowDocument автоматически запускает родительский
контейнер FlowDocumentReader, который размещает содержимое и имеет стандартную
панель управления документом.
Добавьте к решению
новый проект WpfText2 типа WPF Application и
назначьте его стартовым
В декларативный раздел XAML добавьте контейнер <TabControl> с вкладкой <TabItem Header="Text1">
Заполните файл Window1.xaml следующим кодом<Window x:Class="WpfText2.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="LightGray"
Title="Window1" MinHeight="300" MinWidth="300" Height="300" Width="300">
<TabControl>
<TabItem Header="Text1">
<FlowDocument Background="White">
<Paragraph TextAlignment="Center" FontWeight="Bold">
Потоковый
<Span Foreground="Red"> документ</Span>
<Italic>с разбивкой на страницы</Italic>
</Paragraph>
<List MarkerStyle="Decimal" FontFamily="Arial">
<ListItem>
<Paragraph>Первый элемент ListItem</Paragraph>
</ListItem>
<ListItem>
<Paragraph>Второй элемент ListItem</Paragraph>
</ListItem>
<ListItem>
<Paragraph>Третий элемент ListItem</Paragraph>
</ListItem>
</List>
<Paragraph FontSize="12">Класс FlowDocument поддерживает списки, определения
<Bold>
<Span FontFamily="Comic Sans MS" FontSize="12" Foreground="Blue">
семейств шрифтов, цвет
</Span>
</Bold> размеры и стили.
</Paragraph>
</FlowDocument>
</TabItem>
</TabControl>
</Window>
Запустите приложение,
поизменяйте размер окна и разберитесь с кодомРезультат будет таким

Оборачивание элемента FlowDocument в контейнер RichTextBox отключает панель
навигации по тексту.
В контейнер <TabControl> добавьте вкладку <TabItem
Header="Text2" Selector.IsSelected="True"> и заполните ее следующим кодом<TabItem Header="Text2" Selector.IsSelected="True">
<RichTextBox IsReadOnly="True" FontSize="21" >
<FlowDocument Background="White">
<Paragraph TextAlignment="Center" FontWeight="Bold">
Потоковый
<Span Foreground="Red">документ</Span>
<Italic>обернут в RichTextBox</Italic>
</Paragraph>
<List MarkerStyle="LowerLatin" FontFamily="Arial" FontSize="14">
<ListItem>
<Paragraph>Маркер LowerLatin</Paragraph>
</ListItem>
<ListItem>
<Paragraph>Второй элемент ListItem</Paragraph>
</ListItem>
</List>
<List MarkerStyle="Box" FontFamily="Arial" FontSize="14">
<ListItem>
<Paragraph>Маркер Box</Paragraph>
</ListItem>
<ListItem>
<Paragraph>Второй элемент ListItem</Paragraph>
</ListItem>
</List>
<Paragraph FontSize="12">В родительском контейнере RichTextBox
<Bold>
<Span FontFamily="Comic Sans MS" FontSize="12" Foreground="Blue">
включен режим IsReadOnly="True"
</Span>
</Bold> и не появляется полоса прокрутки при длинном тексте
</Paragraph>
</FlowDocument>
</RichTextBox>
</TabItem>
Присоединенный к дескриптору вкладки атрибут Selector.IsSelected="True" позиционирует
ее при открытии окна.
Запустите приложение,
поизменяйте размер окна и разберитесь с кодомРезультат будет таким

Оборачивание элемента FlowDocument в контейнер FlowDocumentScrollViewer по
умолчанию отключает панель инструментов документа и добавляет вертикальную
панель прокрутки, которую можно настраивать. Вертикальная полоса прокрутки
включается с помощью присоединенного свойства. Панель инструментов включается
свойством IsToolBarVisible="True" (по умолчанию IsToolBarVisible="False" ).
FlowDocument - единственный допустимый
дочерний элемент объекта FlowDocumentScrollViewer. В FlowDocumentScrollViewer может быть размещен не более чем один элемент FlowDocument.
В контейнер <TabControl> добавьте
вкладку <TabItem Header="Text3"> и
заполните ее следующим кодом<TabItem Header="Text3">
<FlowDocumentScrollViewer
ScrollViewer.VerticalScrollBarVisibility="Auto"
IsToolBarVisible="False"
>
<FlowDocument Background="White" FontSize="14">
<Paragraph TextAlignment="Center" FontWeight="Bold">
FlowDocument
<Italic>помещен в</Italic>
<Span Foreground="Red">FlowDocumentScrollViewer</Span>
</Paragraph>
<List MarkerStyle="None" FontFamily="Arial">
<ListItem>
<Paragraph>Буря мглою небо кроет</Paragraph>
</ListItem>
<ListItem>
<Paragraph>Вихри снежные крутя.</Paragraph>
</ListItem>
<ListItem>
<Paragraph>То как зверь она завоет</Paragraph>
</ListItem>
<ListItem>
<Paragraph>То заплачет как дитя.</Paragraph>
</ListItem>
</List>
<Paragraph TextAlignment="Left" FontSize="12">Текст
нефикированного формата FlowDocument нужно заключать в параграфы
(абзацы), внутри которых можно применять стилевые элементы.
</Paragraph>
<Paragraph>
<Bold>
<Span FontFamily="Comic Sans MS" FontSize="12" Foreground="Blue">
Буря мглою небо кроет вихри снежные крутя.
<LineBreak />
</Span>
</Bold>
То как зверь она завоет, то заплачет как дитя.
</Paragraph>
</FlowDocument>
</FlowDocumentScrollViewer>
</TabItem>
Присоединенный к дескриптору <FlowDocumentScrollViewer>
атрибут ScrollViewer.VerticalScrollBarVisibility="Auto" обеспечивает
автоматическое появление полосы прокрутки, если текст не помещается на
экране. Атрибуты, установленные в контейнере <FlowDocument>, действуют
по умолчанию на все дочерние элементы, если аналогичные атрибуты в них
не переопределены. В списках маркеры элементов можно менять или вообще
отключать.
Запустите приложение,
поизменяйте размер окна и разберитесь с кодомРезультат будет таким

Использование контейнера FlowDocumentPageViewer для FlowDocument позволяет
представлять документ как одну страницу без средства поиска текста и разбивки
его на страницы и колонки, но оставляет панель изменения масштаба и навигации.
Однако в самом FlowDocument есть свойства, позволяющие настраивать обычный
и многоколоночный текст. Вот некоторые из них
TextAlignment="Justify" - выравнивание текста по обеим границам
колонок (включен по умолчанию)IsHyphenationEnabled="True" - включение расстановки переносов (при наличии
словарей)IsOptimalParagraphEnabled="True" - включение оптимального абзаца, выравнивающего
пробелы между словами за счет разрежения символов в самих словах при режиме TextAlignment="Justify"ColumnGap="25" - ширина между колонками в логических пикселахColumnWidth="150" - предпочтительная (минимальная) ширина колонкиIsColumnWidthFlexible="False" - это значение флага явно запрещает дозаполнять
окно просмотра и устанавливает жесткую ширину колонкиColumnRuleWidth="5" - ширина вертикальных линеек, разделяющих колонки текстаColumnRuleBrush="Red" - цвет линеек
В контейнер <TabControl> добавьте
вкладку <TabItem Header="Text4"> и заполните ее следующим
кодом<TabItem Header="Text4">
<FlowDocumentPageViewer>
<FlowDocument
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="White"
ColumnWidth="150"
ColumnRuleWidth="2"
ColumnRuleBrush="Red"
ColumnGap="30"
IsHyphenationEnabled="True"
IsOptimalParagraphEnabled="True"
>
<Paragraph FontSize="18" FontWeight="Bold" TextAlignment="Center">
Примеры форматирования FlowDocument amp; FlowDocumentPageViewer
</Paragraph>
<Paragraph>
Это абзац с атрибутами по умолчанию.
</Paragraph>
<Paragraph>
Это еще один абзац с атрибутами по умолчанию.
</Paragraph>
<Paragraph FontSize="18">Абзац с FontSize="18"</Paragraph>
<Paragraph FontSize="15">Абзац с FontSize="15"</Paragraph>
<Paragraph FontSize="15">Список lt;List FontFamily="Arial"gt;</Paragraph>
<List FontFamily="Arial">
<ListItem>
<Paragraph>ListItem 1</Paragraph>
</ListItem>
<ListItem>
<Paragraph>ListItem 2</Paragraph>
</ListItem>
<ListItem>
<Paragraph>ListItem 3</Paragraph>
</ListItem>
<ListItem>
<Paragraph>ListItem 4</Paragraph>
</ListItem>
<ListItem>
<Paragraph>ListItem 5</Paragraph>
</ListItem>
</List>
<Paragraph>
<Bold>Это элемент lt;Boldgt; внутри абзаца lt;Paragraphgt;</Bold>
</Paragraph>
<Paragraph>
<Underline>Это элемент Underline внутри абзаца</Underline>
</Paragraph>
<Paragraph>
<Bold>
<Underline>Подчеркнутый внутри полужирного</Underline>
</Bold>
</Paragraph>
<Paragraph>
<Italic>Это элемент lt;Italicgt;</Italic>
</Paragraph>
<Paragraph>
<Span>Элемент Span с настройками по умолчанию</Span>
</Paragraph>
<Paragraph>
<Run>Элемент Run с настройками по умолчанию</Run>
</Paragraph>
<Paragraph FontSize="15">Subscript, Superscript</Paragraph>
<Paragraph>
<Run Typography.Variants="Superscript">This text is Superscripted.</Run>
This text isn't.
</Paragraph>
<Paragraph>
<Run Typography.Variants="Subscript">This text is Subscripted.</Run>
This text isn't.
</Paragraph>
<Paragraph TextIndent="-25" Margin="25,0">
If a font does not support a particular form (such as Superscript)
a default font form will be displayed.
</Paragraph>
<Paragraph FontSize="15">Blocks, breaks, paragraph</Paragraph>
<Section>
<Paragraph>A block section of text</Paragraph>
</Section>
<Section>
<Paragraph>Another block section of text</Paragraph>
</Section>
<Paragraph>
<LineBreak/>
</Paragraph>
<Section>
<Paragraph>... and another section, preceded by a LineBreak</Paragraph>
</Section>
<Section BreakPageBefore="True"/>
<Section>
<Paragraph>... and another section, preceded by a PageBreak</Paragraph>
</Section>
<Paragraph>Finally, a paragraph. Note the break between this paragraph ...</Paragraph>
<Paragraph TextIndent="25">... and this paragraph, and also the left indention.</Paragraph>
</FlowDocument>
</FlowDocumentPageViewer>
</TabItem>
Здесь мы применили основной набор элементов форматирования текста 'на лету'.
Обратите внимание, что в разметке угловые скобки кодируются как в HTML.
Другие управляющие символы разметки кодируются аналогично, например, ' '
кодируется как ' amp; '. Знак подчеркивания ' _ ' считается
служебным для выделения горячих клавиш в меню, поэтому в ином употреблении
должен экранироваться таким же знаком подчеркивания.
Параметры настройки FlowDocument разбивают текст
на колонки, задают ширину колонок, расстояние между ними и вертикальные линейки.
Определение пространств имен в дескрипторе FlowDocument здесь роли
не играет, но должно обязательно присутствовать для успокоения редактора,
если контейнер FlowDocument редактируется оболочкой автономно как внешний
файл документа.
Запустите приложение,
поизменяйте размер окна и разберитесь с кодомРезультат будет таким

Обратите внимание, что в длинных словах кириллический текст объект FlowDocument не переносит, а латиницу - переносит.
Проверьте действие
атрибута IsOptimalParagraphEnabled="True",
включающего оптимальный
параграфСледующий пример взят из MSDN (http://msdn.microsoft.com/ru-ru/library/system.windows.controls.flowdocumentscrollviewer.aspx)
и иллюстрирует дополнительные возможности разметки неформатированного текста
в FlowDocument. Он не содержит кириллицы, поэтому дальше нам пригодится
при решении проблем кодировки.
Добавьте новую вкладку
с приведенным кодом<TabItem Header="Text5" Selector.IsSelected="True">
<FlowDocumentScrollViewer Margin="10" BorderBrush="Black" BorderThickness="1">
<FlowDocument
ColumnWidth="400"
IsOptimalParagraphEnabled="True"
IsHyphenationEnabled="True"
>
<Section FontSize="12">
<Paragraph>
<Bold>Neptune</Bold> (planet), major planet in the solar system, eighth planet
from the Sun and fourth largest in diameter. Neptune maintains an almost constant
distance, about 4,490 million km (about 2,790 million mi), from the Sun. Neptune
revolves outside the orbit of Uranus and for most of its orbit moves inside the
elliptical path of the outermost planet Pluto (see Solar System). Every 248 years,
Pluto’s elliptical orbit brings the planet inside Neptune’s nearly circular orbit
for about 20 years, temporarily making Neptune the farthest planet from the Sun.
The last time Pluto’s orbit brought it inside Neptune’s orbit was in 1979. In
1999 Pluto’s orbit carried it back outside Neptune’s orbit.
<Figure
Width="140" Height="50" Background="GhostWhite"
HorizontalAnchor="PageLeft"
HorizontalOffset="100" VerticalOffset="20"
>
<Paragraph
FontStyle="Italic" TextAlignment="Left"
Background="Beige" Foreground="DarkGreen"
>
Neptune has 72 times Earth's volume...
</Paragraph>
</Figure>
<Floater
Background="GhostWhite"
Width="285" HorizontalAlignment="Left"
>
<Table CellSpacing="5">
<Table.Columns>
<TableColumn Width="155"/>
<TableColumn Width="130"/>
</Table.Columns>
<TableRowGroup>
<TableRow>
<TableCell ColumnSpan="3">
<Paragraph>Neptune Stats</Paragraph>
</TableCell>
</TableRow>
<TableRow Background="LightGoldenrodYellow" FontSize="12">
<TableCell>
<Paragraph FontWeight="Bold">Mean Distance from Sun</Paragraph>
</TableCell>
<TableCell>
<Paragraph>4,504,000,000 km</Paragraph>
</TableCell>
</TableRow>
<TableRow FontSize="12" Background="LightGray">
<TableCell>
<Paragraph FontWeight="Bold">Mean Diameter</Paragraph>
</TableCell>
<TableCell>
<Paragraph>49,532 km</Paragraph>
</TableCell>
</TableRow>
<TableRow Background="LightGoldenrodYellow" FontSize="12">
<TableCell>
<Paragraph FontWeight="Bold">Approximate Mass</Paragraph>
</TableCell>
<TableCell>
<Paragraph>1.0247e26 kg</Paragraph>
</TableCell>
</TableRow>
<TableRow>
<TableCell ColumnSpan="4">
<Paragraph FontSize="10" FontStyle="Italic">
Information from the
<Hyperlink
NavigateUri="http://encarta.msn.com/encnet/refpages/artcenter.aspx"
>
Encarta
</Hyperlink>
web site.
</Paragraph>
</TableCell>
</TableRow>
</TableRowGroup>
</Table>
</Floater>
</Paragraph>
<Paragraph>
Astronomers believe Neptune has an inner rocky core that is surrounded by a vast
ocean of water mixed with rocky material. From the inner core, this ocean extends
upward until it meets a gaseous atmosphere of hydrogen, helium, and trace amounts
of methane. Neptune has four rings and 11 known moons. Even though Neptune's volume
is 72 times Earth’s volume, its mass is only 17.15 times Earth’s mass. Because of
its size, scientists classify Neptune—along with Jupiter, Saturn, and Uranus—as
one of the giant or Jovian planets (so-called because they resemble Jupiter).
</Paragraph>
<Paragraph>
<Figure
Width="140" Height="50"
Background="GhostWhite" TextAlignment="Left"
HorizontalAnchor="PageCenter" WrapDirection="Both"
>
<Paragraph FontStyle="Italic" Background="Beige" Foreground="DarkGreen" >
Neptune has an orbital period of ~20 years...
</Paragraph>
</Figure>
Mathematical theories of astronomy led to the discovery of Neptune. To account for
wobbles in the orbit of the planet Uranus, British astronomer John Couch Adams and
French astronomer Urbain Jean Joseph Leverrier independently calculated the existence
and position of a new planet in 1845 and 1846, respectively. They theorized that the
gravitational attraction of this planet for Uranus was causing the wobbles in Uranus’s
orbit. Using information from Leverrier, German astronomer Johann Gottfried Galle first
observed the planet in 1846.
</Paragraph>
</Section>
</FlowDocument>
</FlowDocumentScrollViewer>
</TabItem>
Запустите приложение
- результат будет таким
Поизменяйте размер
окна и разберитесь с кодомОписание использованных в примере элементов можно найти на http://msdn.microsoft.com/ru-ru/library/system.windows.documents.aspx
Документ нефиксированного формата можно создать заранее в XAML -редакторе, сохранить его в файле и загружать во время выполнения в элемент управления просмотром. Продемонстрируем это на предыдущем примере.
Добавьте в разметку
новую вкладку следующего содержания (атрибут подписки на событие Initialized введите
вручную, чтобы правильно создать обработчик)<TabItem Header="Text6" Selector.IsSelected="True">
<FlowDocumentScrollViewer
Margin="10"
BorderBrush="Black"
BorderThickness="1"
Initialized="FlowDocumentScrollViewer_Initialized"
Name="documentReader" />
</TabItem>
Здесь мы декларативно определили и настроили пустой именованный контейнер
просмотра документа, а сам документ с содержимым FlowDocument загрузим из файла
программно и присоединим к свойству Document этого контейнера просмотра.
Уберите из предыдущей
вкладки атрибут Selector.IsSelected="True", чтобы при запуске приложения
сразу открывалась вкладка Text6
Добавьте к проекту WpfText2 новый XML -файл с именем XMLFile1.xml и измените его расширение c xml на xaml
Выделите новый файл
и измените через панель Properties его свойства на
Скопируйте из предыдущего
примера контейнер FlowDocument вместе с его содержимым в файл XMLFile1.xaml и добавьте атрибуты пространств имен WPF в дескриптор FlowDocumentМы создали, так называемый, свободный файл XAML. Свободный файл XAML - это файл со следующими характеристиками:
В нашем случае содержимое файла XMLFile1.xaml должно стать таким
<FlowDocument
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
ColumnWidth="400"
IsOptimalParagraphEnabled="True"
IsHyphenationEnabled="True"
>
<Section FontSize="12">
<Paragraph>
<Bold>Neptune</Bold> (planet), major planet in the solar system, eighth planet
from the Sun and fourth largest in diameter. Neptune maintains an almost constant
distance, about 4,490 million km (about 2,790 million mi), from the Sun. Neptune
revolves outside the orbit of Uranus and for most of its orbit moves inside the
elliptical path of the outermost planet Pluto (see Solar System). Every 248 years,
Pluto’s elliptical orbit brings the planet inside Neptune’s nearly circular orbit
for about 20 years, temporarily making Neptune the farthest planet from the Sun.
The last time Pluto’s orbit brought it inside Neptune’s orbit was in 1979. In
1999 Pluto’s orbit carried it back outside Neptune’s orbit.
<Figure
Width="140" Height="50" Background="GhostWhite"
HorizontalAnchor="PageLeft"
HorizontalOffset="100" VerticalOffset="20"
>
<Paragraph
FontStyle="Italic" TextAlignment="Left"
Background="Beige" Foreground="DarkGreen"
>
Neptune has 72 times Earth's volume...
</Paragraph>
</Figure>
<Floater
Background="GhostWhite"
Width="285" HorizontalAlignment="Left"
>
<Table CellSpacing="5">
<Table.Columns>
<TableColumn Width="155"/>
<TableColumn Width="130"/>
</Table.Columns>
<TableRowGroup>
<TableRow>
<TableCell ColumnSpan="3">
<Paragraph>Neptune Stats</Paragraph>
</TableCell>
</TableRow>
<TableRow Background="LightGoldenrodYellow" FontSize="12">
<TableCell>
<Paragraph FontWeight="Bold">Mean Distance from Sun</Paragraph>
</TableCell>
<TableCell>
<Paragraph>4,504,000,000 km</Paragraph>
</TableCell>
</TableRow>
<TableRow FontSize="12" Background="LightGray">
<TableCell>
<Paragraph FontWeight="Bold">Mean Diameter</Paragraph>
</TableCell>
<TableCell>
<Paragraph>49,532 km</Paragraph>
</TableCell>
</TableRow>
<TableRow Background="LightGoldenrodYellow" FontSize="12">
<TableCell>
<Paragraph FontWeight="Bold">Approximate Mass</Paragraph>
</TableCell>
<TableCell>
<Paragraph>1.0247e26 kg</Paragraph>
</TableCell>
</TableRow>
<TableRow>
<TableCell ColumnSpan="4">
<Paragraph FontSize="10" FontStyle="Italic">
Information from the
<Hyperlink
NavigateUri="http://encarta.msn.com/encnet/refpages/artcenter.aspx"
>
Encarta
</Hyperlink>
web site.
</Paragraph>
</TableCell>
</TableRow>
</TableRowGroup>
</Table>
</Floater>
</Paragraph>
<Paragraph>
Astronomers believe Neptune has an inner rocky core that is surrounded by a vast
ocean of water mixed with rocky material. From the inner core, this ocean extends
upward until it meets a gaseous atmosphere of hydrogen, helium, and trace amounts
of methane. Neptune has four rings and 11 known moons. Even though Neptune's volume
is 72 times Earth’s volume, its mass is only 17.15 times Earth’s mass. Because of
its size, scientists classify Neptune—along with Jupiter, Saturn, and Uranus—as
one of the giant or Jovian planets (so-called because they resemble Jupiter).
</Paragraph>
<Paragraph>
<Figure
Width="140" Height="50"
Background="GhostWhite" TextAlignment="Left"
HorizontalAnchor="PageCenter" WrapDirection="Both"
>
<Paragraph FontStyle="Italic" Background="Beige" Foreground="DarkGreen" >
Neptune has an orbital period of ~20 years...
</Paragraph>
</Figure>
Mathematical theories of astronomy led to the discovery of Neptune. To account for
wobbles in the orbit of the planet Uranus, British astronomer John Couch Adams and
French astronomer Urbain Jean Joseph Leverrier independently calculated the existence
and position of a new planet in 1845 and 1846, respectively. They theorized that the
gravitational attraction of this planet for Uranus was causing the wobbles in Uranus’s
orbit. Using information from Leverrier, German astronomer Johann Gottfried Galle first
observed the planet in 1846.
</Paragraph>
</Section>
</FlowDocument>
Заполните файл 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;
using System.IO;
namespace WpfText2
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void FlowDocumentScrollViewer_Initialized(object sender, EventArgs e)
{
documentReader.Document = (FlowDocument)XamlReader.
Load(File.OpenRead("XMLFile1.xaml"));
// Альтернативный вариант
//LoadFlowDocumentScrollViewerWithXAMLFile("XMLFile1.xaml");
}
// Альтернативный вариант
void LoadFlowDocumentScrollViewerWithXAMLFile(string fileName)
{
FileStream xamlFile = new FileStream(fileName, FileMode.Open, FileAccess.Read);
FlowDocument content = XamlReader.Load(xamlFile) as FlowDocument;
documentReader.Document = content;
xamlFile.Close();
}
}
}
Здесь мы свойству Document контейнера просмотра FlowDocumentScrollViewer присваиваем
возвращенный классом XamlReader размеченный
документ нефиксированного формата.
Запустите приложение
- получится точно такой же результат, как в предыдущем примере
Проверьте работу закомментированного
альтернативного варианта процедурного кодаПоскольку XAML -формат документов и сама технология WPF являются относительно
новыми, может потребоваться применить WPF к уже наработанному большому массиву HTML -документов. Для этого в WPF имеется класс System.Windows.Controls.WebBrowser.
Его не нужно путать с одноименным классом System.Windows.Forms.WebBrowser технологии Windows Forms. Описание WebBrowser приведено в
http://msdn.microsoft.com/ru-ru/library/system.windows.controls.webbrowser.aspx
В этом упражнении мы познакомимся с применением WebBrowser WPF к просмотру HTML -документов, а также с преобразованием HTML в рассмотренные ранее XAML -документы нефиксированного формата.
Добавьте к решению
командой File/Add/New Project новый проект WpfText3 типа WPF Application и
назначьте его стартовым
В декларативный раздел XAML добавьте контейнер <TabControl> с вкладкой <TabItem Header="HTML1">
Заполните файл Window1.xaml следующим кодом<Window x:Class="WpfText3.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1"
Height="300" Width="300"
Background="LightGray"
>
<TabControl>
<TabItem Header="HTML1">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<WebBrowser Grid.Row="0" Name="webBrowser1" />
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Center">
<Button Width="75" Content="Back" Click="backButton_Click" Margin="0,5,0,0" />
<Button Width="75" Content="Load" Click="loadButton_Click" Margin="5,5,5,0" />
<Button Width="75" Content="Forward" Click="forwardButton_Click" Margin="0,5,0,0" />
</StackPanel>
</Grid>
</TabItem>
</TabControl>
</Window>
Обработчики события Click кнопок заполните так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;
namespace WpfText3
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void loadButton_Click(object sender, RoutedEventArgs e)
{
Microsoft.Win32.OpenFileDialog openFileDialog = new Microsoft.Win32.OpenFileDialog();
openFileDialog.Filter = "HTML Documents (*.htm; *.html)|*.htm;*.html";
openFileDialog.InitialDirectory = System.IO.Directory.GetCurrentDirectory();
openFileDialog.Multiselect=false;
if (openFileDialog.ShowDialog() == false || openFileDialog.FileName == String.Empty)
return;
Uri uri = new Uri(openFileDialog.FileName);
this.webBrowser1.Source = uri;
}
private void backButton_Click(object sender, RoutedEventArgs e)
{
if (this.webBrowser1.CanGoBack)
{
this.webBrowser1.GoBack();
}
}
private void forwardButton_Click(object sender, RoutedEventArgs e)
{
if (this.webBrowser1.CanGoForward)
{
this.webBrowser1.GoForward();
}
}
}
}
Запустите проект -
получится нормальный инструмент просмотра HTML -документов
Обратите внимание, что в предыдущем примере автоматически появляются полосы
прокрутки, если HTML -документ не помещается в окне элемента WebBrowser. Фрагмент
форматированного HTML -текста включать прямо в WebBrowser нельзя, поскольку XAML -редактор оболочки сразу начнет ругаться. Но во время выполнения загружать
файл из кода можно.
В данном примере мы заранее создадим HTML -файл с простым форматированным текстом.
В Solution Explorer вызовите контекстное меню для узла WpfText3 и командой Add/Existing Item добавьте к проекту файл HtmlDoc.htm из прилагаемого каталога Source (или
создайте свой HTML -документ и добавьте его к проекту той же командой)Содержимое файла будет примерно таким
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Untitled Document</title>
<!--
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
-->
</head>
<body style="font-family:Arial, Helvetica, sans-serif">
<h2 align="center"><font color="#FF0000">Это небольшой фрагмент чистого HTML-текста</font></h2>
<ol>
<li>Шрифт Arial</li>
<li><font color="#0000FF">Цвет font color=quot;#0000FFquot;</font></li>
<li><font face="Courier New">Шрифт Courier New </font></li>
<li><b>Стиль полужирный lt;bgt; </b></li>
<li><i>Стиль Italic lt;igt; </i></li>
</ol>
</body>
</html>
Выделите этот файл
и в панели Properties настройте его свойства так
В декларативный раздел XAML в контейнер <TabControl> добавьте новую вкладку <TabItem Header="HTML2">
Заполните ее
следующим скриптом<TabItem Header="HTML2" Selector.IsSelected="True">
<WebBrowser x:Name="webBrowser2" Initialized="webBrowser2_Initialized" />
</TabItem>
Обработчик события Initialized заполните такprivate void webBrowser2_Initialized(object sender, EventArgs e)
{
Uri uri = new Uri(System.IO.Directory.GetCurrentDirectory() +
"\\HtmlDoc.htm", UriKind.Absolute);
this.webBrowser2.Navigate(uri);
}
Здесь мы применили несколько иной способ загрузки файла!
Запустите проект -
получится примерно следующее
Вертикальную полосу прокрутки мне убрать в этом примере не удалось.
Рассмотрим способ подключения HTML -текста из потока. В качестве источника текста будем использовать все тот же файл из предыдущего примера, полагая, что он будет находиться в одном каталоге со сборкой приложения в силу определенных нами ранее для него параметров.
В декларативный раздел XAML в контейнер <TabControl> добавьте новую вкладку <TabItem Header="HTML3">
Заполните ее следующим
скриптом<TabItem Header="HTML3" Selector.IsSelected="True">
<WebBrowser x:Name="webBrowser3" Initialized="webBrowser3_Initialized" />
</TabItem>
Обработчик события Initialized заполните такprivate void webBrowser3_Initialized(object sender, EventArgs e)
{
Uri uri = new Uri("HtmlDoc.htm", UriKind.Relative);
System.IO.Stream source = Application.GetRemoteStream(uri).Stream;
this.webBrowser3.NavigateToStream(source);
}
Запустите проект -
получится то же самое, что в предыдущем примере
В декларативный раздел XAML в контейнер <TabControl> добавьте новую вкладку <TabItem Header="HTML4">
Заполните ее следующим
скриптом<TabItem Header="HTML4" Selector.IsSelected="True">
<WebBrowser x:Name="webBrowser4" Initialized="webBrowser4_Initialized" />
</TabItem>
Обработчик события Initialized заполните такprivate void webBrowser4_Initialized(object sender, EventArgs e)
{
string path = System.IO.Directory.GetCurrentDirectory() + "\\HtmlDoc.htm";
System.IO.StreamReader streamReader = new System.IO.StreamReader(
path, Encoding.GetEncoding(1251));
//MessageBox.Show(streamReader.CurrentEncoding.CodePage.ToString());
string text = streamReader.ReadToEnd();
webBrowser4.NavigateToString(text);
}
Обязательно
закомментируйте или удалите HTML-дескриптор <meta> в документе HtmlDoc.htm, иначе будут проблемы с кодировкой "Кириллица
(Windows) - 1251" в
этом примере HTML4<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Untitled Document</title>
<!--
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
-->
</head>
<body style="font-family:Arial, Helvetica, sans-serif">
<h2 align="center"><font color="#FF0000">Это небольшой фрагмент чистого HTML-текста</font></h2>
<ol>
<li>Шрифт Arial</li>
<li><font color="#0000FF">Цвет font color=quot;#0000FFquot;</font></li>
<li><font face="Courier New">Шрифт Courier New </font></li>
<li><b>Стиль полужирный lt;bgt; </b></li>
<li><i>Стиль Italic lt;igt; </i></li>
</ol>
</body>
</html>
Запустите проект -
получится то же самое, что в предыдущем примере
Мы долго изучали инструменты WPF для работы с текстом нефиксированного формата и даже рассмотрели загрузку XAML -документа из файла. Но реально такие документы тяжело получить: либо их нужно 'загонять' вручную в WPF -проект, либо заранее готовить в отдельном файле. Это большая работа и для ее выполнения требуются определенные знания по пройденному нами материалу, в частности, о внутристрочных элементах.
Для заблаговременной подготовки текста существует наипростейший редактор XamlPad, который поставляется вместе
с оболочкой и его можно найти примерно в следующем месте компьютера (у меня
так, как показано, но я его положил еще и в папку Source ):
C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\XamlPad.exe
Фактически этот редактор проверяет синтаксис XAML -документа и чуток визуализирует его, но никак не автоматизирует работу по созданию.
К счастью, в настоящее время появились более развитые редакторы, которые интегрируются в оболочку или используются отдельно. Это Silverlight и Expression Blend - оба от компании Microsoft и оба платные.
Очень часто обычных возможностей по форматированию текста, используемых в HTML -редакторах, вполне достаточно, особенно для больших документов. Поэтому было бы желательно уметь преобразовывать текст HTML в XAML -документ. Встроенных библиотечных классов для решения этой задачи пока нет, зато есть сторонняя библиотека, автор которой - David Waddleton (http://blogs.msdn.com/DavidWaddleton). Проект этой библиотеки можно свободно загрузить по адресу:
http://waddleton.net/Documents/HtmlConversion.zip
Архив HtmlConversion.zip с проектом и
готовый файл HtmlConversion.dll библиотеки
приведены в прилагаемом каталоге Source. В данном упражнении мы воспользуемся
этой библиотекой 'вслепую', хотя никто не мешает познакомиться с исходным кодом,
распаковав архив с проектом.
Добавьте к решению
новый проект типа WPF Application с именем WpfText4 и
назначьте его стартовым
Для узла References проекта вызовите контекстное меню, вызовите окно Add Reference одноименной
командой и добавьте ссылку на библиотеку HtmlConversion.dll
В панели Solution
Explorer раскройте узел проекта WpfText3 и перетаскиванием мышью скопируйте файл HtmlDoc.htm в корневой узел текущего проекта WpfText4
В панели Properties проверьте, сохранились ли свойства HtmlDoc.htm
Декларативный раздел XAML заполните следующим
скриптом<Window x:Class="WpfText4.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1"
Height="300"
Width="300"
MinHeight="300"
MinWidth="300"
>
<FlowDocumentReader
Name="flowDocumentReader"
ViewingMode="Scroll"
HorizontalContentAlignment="Left"
IsPageViewEnabled="False"
IsPrintEnabled="False"
IsFindEnabled="False"
IsScrollViewEnabled="True"
IsTwoPageViewEnabled="False"
Zoom="75"
ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
Initialized="flowDocumentReader_Initialized"
/>
</Window>
Кодовую часть заполните
так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;
using System.Xml;
using System.IO;
using HTMLConverter;
namespace WpfText4
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void flowDocumentReader_Initialized(object sender, EventArgs e)
{
string path = Directory.GetCurrentDirectory() + "\\HtmlDoc.htm";
StreamReader streamReader = new StreamReader(
path, Encoding.GetEncoding("windows-1251"));
//MessageBox.Show(streamReader.CurrentEncoding.EncodingName);
string text = streamReader.ReadToEnd();
flowDocumentReader.Document = ConvertTextToFlowDocument(text);
}
public static FlowDocument ConvertTextToFlowDocument(string text)
{
try
{
string xaml = HTMLConverter.HtmlToXamlConverter.ConvertHtmlToXaml(text, true);
return XamlReader.Load(new XmlTextReader(new StringReader(xaml))) as FlowDocument;
}
catch (Exception)
{
return null;
}
}
}
}
Запустите проект -
получится почти то же самое, что в предыдущем упражнении
Хоть мы и не видели самого XAML -документа, но трудно отрицать, что в основном
он сформирован верно - вся разметка текста практически сохранилась. Для данного
примера мы произвольно применили элемент FlowDocumentReader, хотя могли выбрать
любой другой из ранее рассмотренных контейнеров.
Обратите
внимание, что для FlowDocumentReader установлено много декларативных
настроек. Стоит с ними поэкспериментировать, чтобы узнать получше, поскольку
эти настройки имеются у всех контейнеров документов нефиксированного формата FlowDocument.
Для больших документов преобразование на лету будет занимать время, да и все
прелести WPF пользователь не увидит. Разумнее заранее подготовить документы
в формате XAML, отредактировать их и уже готовыми подкачивать пользователю.
В этом упражнении мы этим и займемся, для чего опять воспользуемся библиотекой HtmlConversion.dll.
Добавьте к решению
новый проект WPF Application с именем WpfText5 и назначьте его стартовым
Добавьте к проекту
ссылку на библиотеку HtmlConversion.dll
Дескрипторная часть
проекта будет такой<Window x:Class="WpfText5.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1"
Height="300"
Width="300"
MinHeight="300"
MinWidth="300"
ResizeMode="CanResizeWithGrip"
>
<DockPanel Margin="3">
<StackPanel DockPanel.Dock="Bottom"
Orientation="Horizontal"
HorizontalAlignment="Center">
<Button Name="convertToXaml"
Width="85" Content="ConvertToXAML"
Click="convertToXaml_Click" />
<Button Name="loadXaml"
Width="85" Content="LoadXAML"
Margin="5,0,5,0"
Click="loadXaml_Click" />
<Button Name="editXaml"
Width="85"
Content="EditXAML"
Click="editXaml_Click" />
</StackPanel>
<FlowDocumentScrollViewer
x:Name="flowDocumentScrollViewer"
ScrollViewer.VerticalScrollBarVisibility="Visible"
Margin="0,0,0,3" >
<FlowDocument TextAlignment="Left">
<Paragraph TextAlignment="Center" FontWeight="Bold" FontSize="21">
Преобразование формата
</Paragraph>
<List MarkerStyle="Decimal" FontFamily="Arial" FontSize="14">
<ListItem>
<Paragraph>ConvertToXAML - выбрать HTML-файлы и
преобразовать в формат XAML
</Paragraph>
</ListItem>
<ListItem>
<Paragraph>LoadXAML - показать XAML-файл</Paragraph>
</ListItem>
<ListItem>
<Paragraph>EditXAML - редактировать файл в XAMLPad</Paragraph>
</ListItem>
</List>
</FlowDocument>
</FlowDocumentScrollViewer>
</DockPanel>
</Window>
На события Click кнопок
подпишитесь вручную, чтобы оболочка правильно создала обработчики
Кодовая часть проекта
будет такой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.IO;
using Microsoft.Win32;
using HTMLConverter;
using System.Windows.Markup;
namespace WpfText5
{
public partial class Window1 : Window
{
OpenFileDialog openFileDialog = new OpenFileDialog();
public Window1()
{
InitializeComponent();
}
// При конвертации создается подкаталог FilesXAML относительно текущего
private void convertToXaml_Click(object sender, RoutedEventArgs e)
{
openFileDialog.Title = "Select HTML-files";
openFileDialog.Filter = "HTML Documents (*.htm; *.html)|*.htm;*.html";
openFileDialog.Multiselect = true;
if (openFileDialog.ShowDialog() == false || openFileDialog.FileName == String.Empty)
return;
if (!Directory.Exists("FilesXAML"))
Directory.CreateDirectory("FilesXAML");
string[] fileNames = openFileDialog.FileNames;
foreach (String fileName in fileNames)
{
FileStream htmlStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
StreamReader myStreamReader = new StreamReader(htmlStream,
Encoding.GetEncoding(1251));
// Убираем полный путь и расширение
String name = fileName.Substring(0, fileName.LastIndexOf('.'));
int start = name.LastIndexOf('\\');
start = start != -1 ? start + 1 : 0;
name = name.Substring(start);
// Конвертируем
try
{
File.WriteAllText("FilesXAML\\" + name + ".xaml",
HtmlToXamlConverter.ConvertHtmlToXaml(myStreamReader.ReadToEnd(), true),
Encoding.GetEncoding(1251));
}
catch (Exception exc)
{
MessageBox.Show(exc.Message);
}
finally
{
// Сохранили информацию и закрыли потоки
htmlStream.Close();
myStreamReader.Close();
}
}
}
private void loadXaml_Click(object sender, RoutedEventArgs e)
{
openFileDialog.Title = "Select XAML-file";
openFileDialog.Filter = "XAML Documents (*.xaml)|*.xaml";
openFileDialog.Multiselect = false;
if (openFileDialog.ShowDialog() == false || openFileDialog.FileName == String.Empty)
return;
String fileName = openFileDialog.FileName;
try
{
FileStream htmlStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
StreamReader myStreamReader = new StreamReader(htmlStream,
Encoding.GetEncoding(1251));
FlowDocument content = XamlReader.Parse(myStreamReader.ReadToEnd()) as FlowDocument;
flowDocumentScrollViewer.Document = content;
}
catch { }
// Поток закрывать нельзя, разорвется связь с отображением документа
}
private void editXaml_Click(object sender, RoutedEventArgs e)
{
openFileDialog.Title = "Choose a folder with a XamlPad.exe";
openFileDialog.Filter = "XamlPad.exe|XamlPad.exe";
openFileDialog.RestoreDirectory = false;
if (openFileDialog.ShowDialog() == false || !File.Exists("XamlPad.exe"))
return;
String pathXamlPad = System.IO.Path.Combine(
Directory.GetCurrentDirectory(), "XamlPad.exe");
openFileDialog.Title = "Select XAML-file";
openFileDialog.Filter = "XAML Documents (*.xaml)|*.xaml";
openFileDialog.Multiselect = false;
if (openFileDialog.ShowDialog() == false || openFileDialog.FileName == String.Empty)
return;
System.Diagnostics.Process exe = new System.Diagnostics.Process();
exe.StartInfo.FileName = pathXamlPad; //Имя файла для запуска
exe.StartInfo.Arguments = openFileDialog.FileName; //Аргументы
try
{
exe.Start();
}
catch { }
}
}
}
Разберитесь с кодом,
испытайте приложение - в результате получился простой инструмент для преобразований HTML в XAML
Пара HTML -файлов с простой разметкой и готовых XAML -файлов приведена в каталоге Source, но вы можете попробовать конвертировать любой другой файл с не очень
сложной HTML -разметкой.
Конечно, это не промышленная программа Microsoft Silverlight или Microsoft Expression Blend, но элементарные преобразования она выполняет. И самое главное, - мы теперь немножко знаем, как и для чего это делается. Посмотрите, как неуклюже выглядит XamlPad, который находится в прилагаемом каталоге Source. Не удивляйтесь, что кириллицу он не отбражает, зато латиницу отображает прекрасно. В нем нет загрузки файлов, их следует указывать как параметр при запуске. И не нужно этому удивляться, ведь сделан-то он был фирмой Microsoft аж целых четыре года назад.
В данном упражнении приводится несколько примеров обработки текстовых файлов
и их форматирования в FlowDocument программным способом. Мне надоело описывать
пошаговые инструкции, а вам надоело их разбирать, поэтому приведу итоговый
код для исследования.
Что я сделал?
WPFText6 Documents и добавил в него готовый текстовый
файл TextDocument.txt с таким случайным содержимым (приводится в каталоге Source )Здесь знак подчеркивания '_' в начале параграфа является меткой для поиска в одном из примеров.
<Window x:Class="WpfText6.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1"
Height="300"
Width="300"
MinHeight="300"
MinWidth="300"
ResizeMode="CanResizeWithGrip"
Loaded="Window_Loaded"
>
<TabControl>
<TabItem Header="OneParagraph">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<FlowDocumentScrollViewer
DockPanel.Dock="Left"
x:Name="flowDocumentScrollViewer"
ScrollViewer.VerticalScrollBarVisibility="Visible"
>
<FlowDocument Name="flowDoc" TextAlignment="Left" Background="White">
<Paragraph TextAlignment="Center" FontWeight="Bold" FontSize="21">
Чтение одного параграфа
</Paragraph>
<Paragraph Name="text" FontFamily="Arial" />
</FlowDocument>
</FlowDocumentScrollViewer>
<ListBox Grid.Column="1" Name="listBox"
SelectionChanged="listBox_SelectionChanged" />
</Grid>
</TabItem>
<TabItem Header="FullDocument">
<FlowDocument Name="fullDocument" Loaded="fullDocument_Loaded" />
</TabItem>
<TabItem Header="SplitDocument">
<FlowDocumentScrollViewer ScrollViewer.VerticalScrollBarVisibility="Auto">
<FlowDocument Name="splitDocument"
Loaded="splitDocument_Loaded" Background="White" />
</FlowDocumentScrollViewer>
</TabItem>
<TabItem Header="ListDocument">
<FlowDocumentScrollViewer ScrollViewer.VerticalScrollBarVisibility="Auto">
<FlowDocument Name="listDocument"
Initialized="listDocument_Initialized" Background="White" />
</FlowDocumentScrollViewer>
</TabItem>
</TabControl>
</Window>
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.IO;
using Microsoft.Win32;
using System.Windows.Markup;
using System.Collections;
namespace WpfText6
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
// Вынесли как поля для видимости в методах
FileStream myStream;
StreamReader myStreamReader;
String[] arrayText;
private void Window_Loaded(object sender, RoutedEventArgs e)
{
this.Background = Brushes.LightGray;
// Можно вместо разделителя '\\' использовать '/'
String fileName = "Documents/TextDocument.txt";
try
{
myStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
myStreamReader = new StreamReader(myStream, Encoding.GetEncoding(1251));
// Не знаем, какой массив задать, поэтому читаем в коллекцию
// Но можно было и сразу в коллекцию StringBuilder.Append()
ArrayList arrayList = new ArrayList();
while (myStreamReader.EndOfStream != true)
arrayList.Add(myStreamReader.ReadLine());// Читаем построчно
// Копируем ссылки на элементы ArrayList в массив
arrayText = new String[arrayList.Count];
for (int i = 0; i < arrayList.Count; i++)
arrayText[i] = (String)arrayList[i];
// Заполняем ListBox
for (int i = 0; i < arrayText.Length; i++)
{
int pos = arrayText[i].IndexOf('.');
listBox.Items.Add(arrayText[i].Substring(0, pos + 1));
}
listBox.SelectedIndex = 0; // На первый элемент списка
}
catch { } // Один синтаксис!!!
finally
{
// Системные ресурсы надо закрывать
myStream.Close();
myStreamReader.Close();
}
}
private void listBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
text.Inlines.Clear(); // Очищаем предыдущее содержимое
text.Inlines.Add(arrayText[listBox.SelectedIndex]);// Добавляем новое
}
private void fullDocument_Loaded(object sender, RoutedEventArgs e)
{
fullDocument.Background = Brushes.White;// Фон документа программно
for (int i = 0; i < arrayText.Length; i++)
{
Paragraph para = new Paragraph();
para.FontFamily = new FontFamily("Arial");
para.Inlines.Add(arrayText[i]);
fullDocument.Blocks.Add(para);
}
}
String[] textSplit;
private void splitDocument_Loaded(object sender, RoutedEventArgs e)
{
// Можно вместо разделителя '\\' использовать '/'
String fileName = "Documents/TextDocument.txt";
try
{
myStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
myStreamReader = new StreamReader(myStream, Encoding.GetEncoding(1251));
String str = myStreamReader.ReadToEnd();// Читаем весь файл
textSplit = str.Split('_');// Расщепляем строку по метке '_'
// Элемент textSplit[0] получился пустой
}
catch (Exception) { } // Другой синтаксис!!!
finally
{
// Системные ресурсы надо закрывать
myStream.Close();
myStreamReader.Close();
}
// Формируем заголовок программно
Paragraph head = new Paragraph();
head.TextAlignment = TextAlignment.Center;
Run run = new Run("Документ получен расщеплением строки");
run.FontSize = 21;
Bold bold = new Bold(run);
head.Inlines.Add(bold);
splitDocument.Blocks.Add(head);
// Заполняем FlowDocument
splitDocument.FontFamily = new FontFamily("Arial");
for (int i = 1; i < textSplit.Length; i++)
{
Paragraph para = new Paragraph();
para.Inlines.Add(textSplit[i]);
splitDocument.Blocks.Add(para);
}
}
private void listDocument_Initialized(object sender, EventArgs e)
{
// Формируем заголовок
Paragraph head = new Paragraph();
head.TextAlignment = TextAlignment.Center;
Run run = new Run("Нумерованный список OrderList");
run.FontSize = 21;
Bold bold = new Bold(run);
head.Inlines.Add(bold);
listDocument.Blocks.Add(head);
// Создаем и настраиваем список
List list = new List();
list.MarkerOffset = 25;// Отступ от маркеров
list.MarkerStyle = TextMarkerStyle.Decimal;
list.StartIndex = 3; // Нумерация с 3
// Заполняем список дочерними элементами
list.ListItems.Add(new ListItem(new Paragraph(new Run("ListItem 1"))));
list.ListItems.Add(new ListItem(new Paragraph(new Run("ListItem 2"))));
list.ListItems.Add(new ListItem(new Paragraph(new Run("ListItem 3"))));
list.ListItems.Add(new ListItem(new Paragraph(new Run("ListItem 4"))));
list.ListItems.Add(new ListItem(new Paragraph(new Run("ListItem 5"))));
list.ListItems.Add(new ListItem(new Paragraph(new Run("ListItem 6"))));
list.ListItems.Add(new ListItem(new Paragraph(new Run("ListItem 7"))));
// Присоединяем список к документу
listDocument.FontFamily = new FontFamily("Arial");
listDocument.Blocks.Add(list);
}
}
}
Разберитесь с кодом,
или выкиньте мой и сочините свой, но чтобы все работало!Результаты по примерам будут такими:
![]() |
![]() |
![]() |
![]() |
Компьютерные технологии изменяются так стремительно, что некоторым студентам самое время подумать - не пересесть ли с компьютера за штурвал комбайна или не стать ли водителем кобылы. А что, Зелинский, это мысль! Будешь давать стране угля, и дров неналомаешь. Семью обеспечишь, да еще и звезду героя соцтруда могут дать. А у нас, программистов, - одни мозоли в голове, в карманах - вши на арканах, а у преподавателей от таких "студентов" - еще и головная боль впридачу!!! Отпусти нас, Зелинский!
Один из таких комбайнеров написал про меня в Интернете - молодой писака, писательский талант прорезался, на мемуары потянуло, распирать начало. Лучше бы почитывал пока, журналюга... Спасибо, хоть слова не переврал, и то благодаря все тому же Copy-Paste. Почитайте, вам будет поучительно, может станете больше прислушиваться к тому, что я постоянно говорю "Разберитесь с кодом":
http://blogs.mail.ru/mail/vitaliy2525/31E7226B44550EB4.html#
Пописывающий сетует, что что-то делал своими собственными ручками и все работало, но лень было в этом разбираться. А через несколько лет созрел и оказалось, что это красиво - вкусно - полезно. Так причем здесь Снетков?
"Окликнешь, тихо подойдешь, попросишь сторублевку... Причем здесь нож, причем грабеж? - меняй формулировку..." Высоцкий В.С.
Зреть нужно быстрее. Научить ПРОГРАММИРОВАТЬ можно только тех, кто сам этого хочет. Кода я привожу много, на любой вкус и цвет. Разбирайтесь, экспериментируйте, спрашивайте! Но не говорите, что все так плохо и только 'приколы' хороши - это непорядочно.
Высшее профессиональное образование - это не школа благородных девиц. И я не приставленный к ней надзиратель, а свободный преподаватель. Классики, и те уже попритихли. Как научить за мизерное количество часов (и зарплату...)? Заставлять покупать учебники по тысячу рублей штука? Так ведь редко же встречаются целиком стоющие - в одних одно, в других - другое, а большей частью - один хлам.
Взгляните, например, на этот, далеко не полный, ряд 'орудий пристрастья' современного программиста: C#, C++, MFC, VCL, .NET Framework, DirectX, OpenGL, XNA, ADO.NET, SQL, MySQL, SQL Server, Access, Crystal Reports, ASP.NET, HTML, XAML, XML, Windows Forms, WPF, PHP, Ajaxs, сами оболочки C++Builder и MS Visual Studio и т.д. А ведь все это - и есть объектно-ориентированное программирование! И сколько же тысяч нужно заплатить вашим родителям, если все это покупать, чтобы держать себя в форме?
Некоторые из вас и не заметили, что уже пощупали собственными ручками то, о чем ранее даже и не слышали. Все оплачено и налито, только пей. От ' такой методики ' еще никому не поплохело! Знаю, для 'непьющих' хватило бы и Бэйсика, или программирования на листочке, или сразу зачета? Так зачем тогда пришли и на какие средства в дальнейшем собираетесь жить, позвольте спросить, когда ваши родители состарятся и уйдут?
Я не программист, я их уже много лет только готовлю (с перцем, с луком, по собственному рецепту, на приспособах домашнего производства). Есть они не только в Красноярске, можно встретить в Новосибирске, Томске, Железногорске и т.д., и даже... - в Силиконовой долине. Моя ли в том вина, что иногда попадаются подпорченные продукты (я их сам не выбираю), или те, кто сел не в свои сани?
Когда я был маленький, у меня тоже была бабушка. Это было почти вчера, но время летит так быстро: где сейчас маленький, где эта бабушка... Имейте и вы это ввиду - не минет никого чаша сия и нужно все делать вовремя, чтобы успеть состояться в жизни, а не балду гонять! Так что - тужтесь сами, да посильнее, вам 'рожать'. А я на своем месте - стою на вспоможении... (хочешь - напрягайся, буду помогать! не хочешь - дело хозяйское)

Все необходимые для выполнения данной работы программы можно найти в прилагаемом каталоге.
При изучении любого средства программирования используют примеры, которые иллюстрируют применение этого средства. Различают примеры двух видов:
В наших упражнениях рассматриваются преимущественно примеры технологий.
Текст и рисунки - главные информационные составляющие любого приложения. WPF имеет все стандартные элементы, необходимые для работы с текстом. Для простых случаев используются упрощенные элементы представления текста
Label - меткаTextBlock - текстовый блокTextBox - текстовое полеPasswordBox - поле пароляДля более сложных случаев используются высокоразвитые элементы работы с документами. WPF разделяет текстовые документы на две основные категории на основе их предполагаемого использования:
Документы фиксированного формата предназначены для приложений,
требующих точного представления в режиме WYSIWYG (режим точного отображения
- 'что вижу то и имею'), независимо от используемого дисплея или принтера.
Документы фиксированного формата обычно используются при подготовке публикаций
с помощью настольных издательских средств, обработке текста и разметке формы,
где строгое соблюдение исходного дизайна страницы является обязательным. Содержимое
документов фиксированного формата поддерживается классом FixedDocument, а для
просмотра используется класс DocumentViewer.
Документы фиксированного формата, как часть макета, поддерживает точное позиционирование содержимого элементов, независимо от используемых устройств отображения или печати. Например, страница формата фиксированного документа, просматриваемая на экране с разрешением 96 точек на дюйм, будет отображаться точно так же на выводе лазерного принтера с разрешением 600 точек на дюйм или устройстве фотовывода с разрешением 4800 точек на дюйм. Макет страницы остается неизменным во всех случаях, в то время как качество документа повышается в соответствии с возможностями каждого устройства.
Документы нефиксированного формата предназначены для оптимизации просмотра и удобочитаемости и наиболее удобны в использовании, когда простота чтения является основным требованием сценария документа. Вместо предварительно определенного макета, документы нефиксированного формата динамически изменяют и переформатируют свое содержимое на основе переменных времени выполнения, таких как размер окна и разрешение устройства, и дополнительных пользовательских настроек.
В зависимости от среды выполнения, документы нефиксированного формата оптимизируют просмотр и чтение для пользователя. Например, один тот же документ нефиксированного формата будет динамически переформатирован для оптимальной удобочитаемости как на 19-дюймовом экране с высоким разрешением, так и на небольшом 2x3-дюймовом экране карманного ПК. Кроме того, документы нефиксированного формата имеют множество встроенных возможностей, включая поиск, просмотр режимов оптимизации удобочитаемости и возможность изменения размера и вида шрифтов.
Документы нефиксированного формата представлены классом содержимого FlowDocument.
Этот класс обеспечивает размещение и форматирование содержимого потока с такими
дополнительными свойствами документов, как разбивка на страницы и столбцы.
Для отображения, редактирования и навигации по документу используются
классы-контейнеры
RichTextBox - текстовое поле с расширенными возможностямиFlowDocumentScrollViewer - текстовый блок с расширенным содержимым
и управляемой полосой прокруткиFlowDocumentPageViewer - дает возможность просматривать документ постранично
и имеет привычные навигационные элементыFlowDocumentReader - элемент управления, в котором пользователь сам вибирает
способ просмотра документа: одностраничный, многостраничный или с прокруткойЛюбой из этих классов может иметь только один элемент содержимого FlowDocument, который адресуется их свойством Document. Если содержимое не
загружено в контейнер отображения, то свойство Document имеет значение null.
В данной лабораторной работе рассматриваются средства WPF для представления текста нефиксированного формата.
Текстовые элементы Label, TextBlock, TextBox, PasswordBox обычно
используются для создания небольшого текста в интерфейсе пользователя. Они
обладают достаточными для этого возможностями. Но отображать большие потоки
текста они непредназначены.
Создайте решение WpfApp с
проектом WpfText1 и назначьте его стартовым
Добавьте к проекту
новый файл с именем FontPropertyLists.cs 
Заполните файл FontPropertyLists.cs следующим кодомusing System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Media;
namespace WpfText1
{
/// <summary>
/// Код класса из примера MSDN
/// </summary>
public class FontPropertyLists
{
static Collection<FontFamily> fontFaces;
static Collection<FontStyle> fontStyles;
static Collection<FontWeight> fontWeights;
static Collection<double> fontSizes;
static int maxFontSizes = 36;
/// <summary>
/// Заполняет коллекцию доступных системе FontFamily
/// </summary>
public static ICollection<FontFamily> FontFaces
{
get
{
if (fontFaces == null) fontFaces = new Collection<FontFamily>();
foreach (FontFamily fontFamily in Fonts.SystemFontFamilies)
{
fontFaces.Add(fontFamily);
}
return fontFaces;
}
}
/// <summary>
/// Заполняет коллекцию доступных FontStyles
/// </summary>
public static ICollection FontStyles
{
get
{
if (fontStyles == null)
{
fontStyles = new Collection<FontStyle>();
fontStyles.Add(System.Windows.FontStyles.Normal);
fontStyles.Add(System.Windows.FontStyles.Oblique);
fontStyles.Add(System.Windows.FontStyles.Italic);
}
return fontStyles;
}
}
/// <summary>
/// Заполняет коллекцию доступных FontWeight
/// </summary>
public static ICollection FontWeights
{
get
{
if (fontWeights == null)
{
fontWeights = new Collection<FontWeight>();
Unique(System.Windows.FontWeights.Thin);
Unique(System.Windows.FontWeights.Light);
Unique(System.Windows.FontWeights.Regular);
Unique(System.Windows.FontWeights.Normal);
Unique(System.Windows.FontWeights.Medium);
Unique(System.Windows.FontWeights.Heavy);
Unique(System.Windows.FontWeights.SemiBold);
Unique(System.Windows.FontWeights.DemiBold);
Unique(System.Windows.FontWeights.Bold);
Unique(System.Windows.FontWeights.Black);
Unique(System.Windows.FontWeights.ExtraLight);
Unique(System.Windows.FontWeights.ExtraBold);
Unique(System.Windows.FontWeights.ExtraBlack);
Unique(System.Windows.FontWeights.UltraLight);
Unique(System.Windows.FontWeights.UltraBold);
Unique(System.Windows.FontWeights.UltraBlack);
}
return fontWeights;
}
}
static void Unique(FontWeight fontWeight)
{
if (fontWeights.IndexOf(fontWeight) == -1)
fontWeights.Add(fontWeight);
}
/// <summary>
/// Заполняет коллекцию доступных FontSizes
/// </summary>
public static Collection<double> FontSizes
{
get
{
if (fontSizes == null)
{
fontSizes = new Collection<double>();
for (double i = 8; i <= maxFontSizes; i++) fontSizes.Add(i);
}
return fontSizes;
}
}
// Методы для преобразования из TypeName в Type
public static bool CanParseFontStyle(string fontStyleName)
{
try
{
FontStyleConverter converter = new FontStyleConverter();
converter.ConvertFromString(fontStyleName);
return true;
}
catch
{
return false;
}
}
public static FontStyle ParseFontStyle(string fontStyleName)
{
FontStyleConverter converter = new FontStyleConverter();
return (FontStyle)converter.ConvertFromString(fontStyleName);
}
public static bool CanParseFontWeight(string fontWeightName)
{
try
{
FontWeightConverter converter = new FontWeightConverter();
converter.ConvertFromString(fontWeightName);
return true;
}
catch
{
return false;
}
}
public static FontWeight ParseFontWeight(string fontWeightName)
{
FontWeightConverter converter = new FontWeightConverter();
return (FontWeight)converter.ConvertFromString(fontWeightName);
}
}
}
Заполните файл Window1.xaml следующей разметкой<Window x:Class="WpfText1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1"
Background="LightGray"
Height="300"
Width="300"
MinHeight="300"
MinWidth="300"
ResizeMode="CanResizeWithGrip"
WindowStartupLocation="CenterScreen"
FocusManager.FocusedElement="{Binding ElementName='fontSizeListBox'}"
>
<TabControl>
<!--Вкладка Label-->
<TabItem Header="Label">
<!--Сетка 4x3-->
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="60" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<!--Пропорции ширины столбцов-->
<ColumnDefinition Width="2.7*" />
<ColumnDefinition Width="1.3*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Border
Grid.Row="0" Grid.ColumnSpan="3"
BorderThickness="3"
BorderBrush="Violet"
>
<Label
VerticalContentAlignment="Center"
HorizontalContentAlignment="Center"
Foreground="Red"
FontWeight="{Binding ElementName=fontWeightListBox, Path=SelectedItem}"
FontSize="{Binding ElementName=fontSizeListBox, Path=SelectedItem}"
FontFamily="{Binding ElementName=fontFamilyListBox, Path=SelectedItem}"
Content="Элемент Label"
/>
</Border>
<Label
Grid.Row="1" Grid.Column="0"
HorizontalContentAlignment="Center"
Content="FontFamily:"
/>
<TextBox
Grid.Row="2" Grid.Column="0"
Name="fontFamilyTextBox"
Text="{Binding ElementName=fontFamilyListBox, Path=SelectedItem}"
TextChanged="fontFamilyTextBox_TextChanged"
/>
<ListBox
Grid.Row="3" Grid.Column="0"
Name="fontFamilyListBox" SelectedIndex="0"
/>
<Label
Grid.Row="1" Grid.Column="1"
HorizontalContentAlignment="Center"
Content="FontWeight:"
/>
<TextBox
Grid.Row="2" Grid.Column="1"
Name="fontWeightTextBox"
Text="{Binding ElementName=fontWeightListBox, Path=SelectedItem}"
TextChanged="fontWeightTextBox_TextChanged"
/>
<ListBox
Grid.Row="3" Grid.Column="1"
Name="fontWeightListBox" SelectedIndex="0"
/>
<Label
Grid.Row="1" Grid.Column="2"
HorizontalContentAlignment="Center"
Content="FontSize:"
/>
<TextBox
Grid.Row="2" Grid.Column="2"
Name="fontSizeTextBox"
Text="{Binding ElementName=fontSizeListBox, Path=SelectedItem}"
TextChanged="fontSizeTextBox_TextChanged"
/>
<ListBox
Grid.Row="3" Grid.Column="2"
Name="fontSizeListBox" SelectedIndex="0"
/>
</Grid>
</TabItem>
</TabControl>
</Window>
Зарегистрированные
в элементах TextBox обработчики событий TextChanged заполните в файле Window1.xaml.csusing 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;
namespace WpfText1
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
// Заполняем коллекции и подключаем их к спискам ListBox
this.fontFamilyListBox.ItemsSource = FontPropertyLists.FontFaces;
this.fontWeightListBox.ItemsSource = FontPropertyLists.FontWeights;
this.fontSizeListBox.ItemsSource = FontPropertyLists.FontSizes;
// Выполняется после XAML
this.fontSizeListBox.SelectedIndex = this.fontSizeListBox.Items.Count - 1;
this.fontSizeListBox.ScrollIntoView(this.fontSizeListBox.Items.Count - 1);
}
// Сокрытие унаследованных от Window одноименных свойств
new public FontFamily FontFamily
{
get { return (FontFamily)this.fontFamilyListBox.SelectedItem; }
set
{
this.fontFamilyListBox.SelectedItem = value; // Выделить
this.fontFamilyListBox.ScrollIntoView(value); // Прокрутить до видимого
}
}
new public FontWeight FontWeight
{
get { return (FontWeight)this.fontWeightListBox.SelectedItem; }
set
{
this.fontWeightListBox.SelectedItem = value; // Выделить
this.fontWeightListBox.ScrollIntoView(value); // Прокрутить до видимого
}
}
new public double FontSize
{
get { return (double)this.fontSizeListBox.SelectedItem; }
set
{
this.fontSizeListBox.SelectedItem = value; // Выделить
this.fontSizeListBox.ScrollIntoView(value); // Прокрутить до видимого
}
}
private void fontFamilyTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
// Привести ListBox в соответствие с содержимым TextBox
this.FontFamily = new FontFamily(this.fontFamilyTextBox.Text);
}
private void fontWeightTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
// Привести ListBox в соответствие с содержимым TextBox
if (FontPropertyLists.CanParseFontWeight(this.fontWeightTextBox.Text))
{
this.FontWeight = FontPropertyLists.ParseFontWeight(this.fontWeightTextBox.Text);
}
}
private void fontSizeTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
// Привести ListBox в соответствие с содержимым TextBox
double fontSize;
if (double.TryParse(this.fontSizeTextBox.Text, out fontSize))
{
this.FontSize = fontSize; // В поле действительно число
}
}
}
}
Запустите проект -
получим инструмент для просмотра основных атрибутов библиотечного текстового
элемента Label
Обратите внимание,
как компоновка окна сохраняется при изменении его размеров и что окно имеет
минимальный размер. Разберитесь с кодом разметки и процедурным кодом C#Текстовый элемент TextBlock поддерживает способы программирования Windows и стили Web. Он обладает развитыми средствами анимации и динамического программирования
стилей. Настройки элемента можно задавать в декларативном ( XAML ) и процедурном
( C# ) режимах. Проиллюстрируем некоторые возможности элемента TextBlock на примере.
Добавьте в файл Window1.xaml проекта WpfText1 вкладку TextBlock1 со следующей разметкой<!--Вкладка TextBlock1-->
<TabItem Header="TextBlock1">
<Border Background="Black">
<Border Margin="25" CornerRadius="50" BorderThickness="2" BorderBrush="Yellow">
<!--Радиальный градиент заливки Border-->
<Border.Background>
<RadialGradientBrush>
<GradientStop Color="Blue" Offset="0.1" />
<!--Непрозрачный alfa-канал и 000000 (Black)-->
<GradientStop Color="#FF000000" Offset="1.2" />
</RadialGradientBrush>
</Border.Background>
<!--Анимация градиентной подсветки внешнего контура Border-->
<Border.BitmapEffect>
<OuterGlowBitmapEffect x:Name="glow" GlowColor="Yellow" GlowSize="0" />
</Border.BitmapEffect>
<Border.Triggers>
<EventTrigger RoutedEvent="Border.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="glow"
Storyboard.TargetProperty="GlowSize"
From="30" To="0" Duration="0:0:1"
AutoReverse="True"
RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Border.Triggers>
<!--Текстовый блок-->
<TextBlock Name="text"
Text=""
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="White" FontSize="16"
Initialized="text_Initialized"
>
<TextBlock.Inlines>
<Bold>Это текстовый</Bold>
<LineBreak />
<Italic>элемент TextBlock</Italic>
<LineBreak />
<Run FontWeight="Bold" Foreground="Red">
Очень
</Run>
<Run FontStyle="Italic" TextDecorations="Underline" Foreground="Yellow">
красивый
</Run>
</TextBlock.Inlines>
<!--Действия в TextBlock-->
<TextBlock.LayoutTransform>
<RotateTransform x:Name="rotateTransform" Angle="0" />
</TextBlock.LayoutTransform>
<TextBlock.Triggers>
<!--Анимация поворота-->
<EventTrigger RoutedEvent="TextBlock.MouseDown">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="rotateTransform"
Storyboard.TargetProperty="Angle"
From="0" To="360" Duration="0:0:3"
RepeatBehavior="2x"
/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<!--Анимация изменения размера при заходе мыши-->
<EventTrigger RoutedEvent="TextBlock.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="text"
Storyboard.TargetProperty="FontSize"
To="26" Duration="0:0:0.2"
/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<!--Анимация изменения размера при сходе мыши-->
<EventTrigger RoutedEvent="TextBlock.MouseLeave">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="text"
Storyboard.TargetProperty="FontSize"
Duration="0:0:1"
/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</TextBlock.Triggers>
</TextBlock>
</Border>
</Border>
</TabItem>
Добавьте в процедурную
часть (файл Window1.xaml.cs ) код обработчика события Initialized элемента TextBlock, который в динамическом режиме дополняет декларативную настройку
этого текстового элементаprivate void text_Initialized(object sender, EventArgs e)
{
// Добавляем в TextBlock строку
Run run = new Run("\nDynamic");
run.FontFamily = new FontFamily("Curlz MT");
text.Inlines.Add(run);
run = new Run("Text");
run.FontFamily = new FontFamily("Comic Sans MS");
run.Foreground = Brushes.Aqua;
text.Inlines.Add(new Bold(run));
}
Запустите проект -
получим анимационный текст с персональными настройками стилей
Изучите приведенный
кодТекст в элементе TextBlock можно закрашивать произвольным рисунком.
В панели Solution
Explorer создайте
для корня дерева проекта папку Images и добавьте в нее (командой Add ) из
прилагаемого к работе каталога Source файлы Image1.jpg и Image2.png
Добавьте в файл Window1.xaml новую вкладку со следующей разметкой<!--Вкладка TextBlock2-->
<TabItem Header="TextBlock2">
<Canvas Background="Black">
<TextBlock
Canvas.Left = "10"
Canvas.Top="10"
FontFamily="Arial"
FontSize="36"
Foreground="Red"
Text="SolidColorBrush"
/>
<TextBlock
Canvas.Left = "10"
Canvas.Top="50"
FontFamily="Arial"
FontSize="75"
Text="Image1">
<TextBlock.Foreground>
<ImageBrush ImageSource="Images\Image1.jpg" Opacity=".9" />
</TextBlock.Foreground>
</TextBlock>
<TextBlock
Canvas.Left = "10"
Canvas.Top="130"
FontFamily="Arial"
FontSize="75"
Text="Image2">
<TextBlock.Foreground>
<ImageBrush ImageSource="Images/Image2.png" />
</TextBlock.Foreground>
</TextBlock>
</Canvas>
</TabItem>
Запустите приложение
- должно получиться следующее
Изучите приведенный
кодЕсли явно определить ширину элемента TextBlock и задать атрибут TextWraping="Wrap",
то блочный текст будет автоматически размещаться внутри заданной ширины.
Добавьте в файл Window1.xaml новую вкладку со следующей разметкой<!--Вкладка TextBlock3-->
<!-- Элемент TextBlock с переносом строк -->
<TabItem Header="TextBlock3">
<Grid Background="White">
<TextBlock
TextWrapping="Wrap"
FontSize="18"
TextAlignment="Center" >
Если в элементе TextBlock задать атрибут TextWraping="Wrap",
то блочный текст будет автоматически размещаться внутри
заданной ширины
<LineBreak />
<Run Foreground="Red" FontSize="28" FontFamily="Monotype Corsiva">
Панель Grid здесь введена для создания белого фона
</Run>
<LineBreak />
<Run FontSize="12">
Общие настройки родителя действуют на потомков до тех пор,
пока не будут переопределены внутри самих потомков
</Run>
</TextBlock>
</Grid>
</TabItem>
Запустите приложение
- должно получиться следующее
Изучите приведенный
кодИногда нет уверенности в том, что на компьютере пользователя есть нужные шрифты, с использованием которых программист разрабатывает интерфейс. В таком случае шрифты можно поставлять вместе с приложением.
Перейдите в раздел "Панель
управления", откройте папку " Шрифты " и перетащите мышью шрифт,
например, "Source )
В панели Solution
Explorer создайте в корне проекта папку Fonts, выделите ее и добавьте командой Project/Add Existing Item файл шрифта MTCORSVA.TTF
Добавьте в файл Window1.xaml новую вкладку со следующей разметкой<!--Вкладка TextBlock4-->
<!-- Элемент TextBlock с дополнительным шрифтом -->
<TabItem Header="TextBlock4">
<Grid Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock
FontFamily="Fonts/MTCORSVA.TTF#Monotype Corsiva"
FontSize="20"
TextWrapping="Wrap"
TextAlignment="Justify"
Margin="10"
ToolTip="Элемент TextBlock с дополнительным шрифтом">
Шрифт для этого текста подключен явно и поставляется
вместе с приложением на тот случай, если у бедного
пользователя компьютер окажется еще беднее.
</TextBlock>
<TextBlock Grid.Row="1" Margin="10" TextWrapping="Wrap">
В этом блоке текста используется шрифт по умолчанию и
нет всплывающей подсказки ToolTip, а в верхнем блоке есть
</TextBlock>
</Grid>
</TabItem>
Запустите приложение
- должно получиться следующее
Изучите приведенный
код
Добавьте к проекту
следующую вкладку со скриптовым кодом<!--TextBox и PasswordBox-->
<TabItem Header="TextBox" Selector.IsSelected="True">
<StackPanel VerticalAlignment="Center" Margin="10">
<TextBlock HorizontalAlignment="Center">
<Run FontSize="14" FontWeight="Bold">
Элементы PasswordBox и TextBox
</Run>
</TextBlock>
<Grid Height="20" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="Поле PasswordBox: " VerticalAlignment="Center" />
<PasswordBox Grid.Column="1" Name="passwordBox" />
</Grid>
<Grid Height="20" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="Поле TextBox: " VerticalAlignment="Center" />
<TextBox Grid.Column="1" Name="textBox"></TextBox>
</Grid>
<Grid Height="20" />
<Grid HorizontalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="5" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Content="Показать" Click="Button_Click" />
<ToggleButton Grid.Column="2" Name="toggleButton" Content="EnabledPassword"
Checked="toggleButton_Checked" Unchecked="toggleButton_Checked"/>
</Grid>
</StackPanel>
</TabItem>
Выделенную в разметке
кнопок регистрацию обработчиков наберите вручную
Добавьте в кодовую
часть следующие обработчикиprivate void Button_Click(object sender, RoutedEventArgs e)
{
textBox.Text = passwordBox.Password;
}
bool flagState = true;
Brush color;
private void toggleButton_Checked(object sender, RoutedEventArgs e)
{
// Сохраняем первоначальный цвет кнопки
if (flagState)
{
color = toggleButton.Background;
flagState = false;
}
if (toggleButton.IsChecked == true)
{
passwordBox.IsEnabled = false;
toggleButton.Background = Brushes.Red;
}
else
{
passwordBox.IsEnabled = true;
toggleButton.Background = color;
}
}
Запустите приложение,
поизменяйте размер окна и разберитесь с кодомРезультат будет таким

Классы-упаковки содержимого нефиксированного формата
FlowDocumentReaderRichTextBox FlowDocumentScrollViewer FlowDocumentPageViewer имеют дочерний элемент FlowDocument. В свою очередь, FlowDocument задает строгую
модель содержимого для своего дочернего содержимого. Дочерние элементы верхнего
уровня, содержащиеся в FlowDocument, должны быть производными от Block и называются блочными. Допустимыми дочерними элементами верхнего уровня в FlowDocument являются
следующие блоки:
| Блок | Описание |
|---|---|
Paragraph |
Содержит текст, возможно форматированный. |
List |
Содержит списки разного типа (нумерованный, маркированный и т. д.). |
Table |
Содержит таблицы, похожие на таблицы Microsoft Word или HTML. |
BlockUIContainer |
Содержит различные элементы пользовательского интерфейса, становящиеся частью размещения. |
Section |
Содержит группу прочих блоков. Разделы удобны для применения общих атрибутов к группам блоков, например, одни и те же атрибуты шрифта для нескольких абзацев. |
Внутри блоков дополнительное форматирование текста обеспечивается элементами, которые называются внутристрочными элементами. К ним относятся
BoldItalicLineBreakListListItemParagraphRunSectionSpanUnderlineВнутристрочные элементы могут быть вложенными друг в друга внутри блока или вместе с родительским блоком вложены в другой блок.
Некоторые элементы могут дополнительно настраиваться, например, такими атрибутами, как
BreakPageBefore=True" - начать с новой страницыFontSize="24" - размер шрифтаTypography .Variants="Superscript " - надстрочныйTypography .Variants="Subscript" - подстрочныйTextIndent="25" - отступ первой строки блокаTextIndent="-15" - выступ первой строки блокаMargin="20,0,0,0" - TextAlignment="Center" - текст посредине контейнера
рендеринга (представления)MarkerStyle="None" - тип маркера в элементе List Создание экземпляра класса FlowDocument автоматически запускает родительский
контейнер FlowDocumentReader, который размещает содержимое и имеет стандартную
панель управления документом.
Добавьте к решению
новый проект WpfText2 типа WPF Application и
назначьте его стартовым
В декларативный раздел XAML добавьте контейнер <TabControl> с вкладкой <TabItem Header="Text1">
Заполните файл Window1.xaml следующим кодом<Window x:Class="WpfText2.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="LightGray"
Title="Window1" MinHeight="300" MinWidth="300" Height="300" Width="300">
<TabControl>
<TabItem Header="Text1">
<FlowDocument Background="White">
<Paragraph TextAlignment="Center" FontWeight="Bold">
Потоковый
<Span Foreground="Red"> документ</Span>
<Italic>с разбивкой на страницы</Italic>
</Paragraph>
<List MarkerStyle="Decimal" FontFamily="Arial">
<ListItem>
<Paragraph>Первый элемент ListItem</Paragraph>
</ListItem>
<ListItem>
<Paragraph>Второй элемент ListItem</Paragraph>
</ListItem>
<ListItem>
<Paragraph>Третий элемент ListItem</Paragraph>
</ListItem>
</List>
<Paragraph FontSize="12">Класс FlowDocument поддерживает списки, определения
<Bold>
<Span FontFamily="Comic Sans MS" FontSize="12" Foreground="Blue">
семейств шрифтов, цвет
</Span>
</Bold> размеры и стили.
</Paragraph>
</FlowDocument>
</TabItem>
</TabControl>
</Window>
Запустите приложение,
поизменяйте размер окна и разберитесь с кодомРезультат будет таким

Оборачивание элемента FlowDocument в контейнер RichTextBox отключает панель
навигации по тексту.
В контейнер <TabControl> добавьте вкладку <TabItem
Header="Text2" Selector.IsSelected="True"> и заполните ее следующим кодом<TabItem Header="Text2" Selector.IsSelected="True">
<RichTextBox IsReadOnly="True" FontSize="21" >
<FlowDocument Background="White">
<Paragraph TextAlignment="Center" FontWeight="Bold">
Потоковый
<Span Foreground="Red">документ</Span>
<Italic>обернут в RichTextBox</Italic>
</Paragraph>
<List MarkerStyle="LowerLatin" FontFamily="Arial" FontSize="14">
<ListItem>
<Paragraph>Маркер LowerLatin</Paragraph>
</ListItem>
<ListItem>
<Paragraph>Второй элемент ListItem</Paragraph>
</ListItem>
</List>
<List MarkerStyle="Box" FontFamily="Arial" FontSize="14">
<ListItem>
<Paragraph>Маркер Box</Paragraph>
</ListItem>
<ListItem>
<Paragraph>Второй элемент ListItem</Paragraph>
</ListItem>
</List>
<Paragraph FontSize="12">В родительском контейнере RichTextBox
<Bold>
<Span FontFamily="Comic Sans MS" FontSize="12" Foreground="Blue">
включен режим IsReadOnly="True"
</Span>
</Bold> и не появляется полоса прокрутки при длинном тексте
</Paragraph>
</FlowDocument>
</RichTextBox>
</TabItem>
Присоединенный к дескриптору вкладки атрибут Selector.IsSelected="True" позиционирует
ее при открытии окна.
Запустите приложение,
поизменяйте размер окна и разберитесь с кодомРезультат будет таким

Оборачивание элемента FlowDocument в контейнер FlowDocumentScrollViewer по
умолчанию отключает панель инструментов документа и добавляет вертикальную
панель прокрутки, которую можно настраивать. Вертикальная полоса прокрутки
включается с помощью присоединенного свойства. Панель инструментов включается
свойством IsToolBarVisible="True" (по умолчанию IsToolBarVisible="False" ).
FlowDocument - единственный допустимый
дочерний элемент объекта FlowDocumentScrollViewer. В FlowDocumentScrollViewer может быть размещен не более чем один элемент FlowDocument.
В контейнер <TabControl> добавьте
вкладку <TabItem Header="Text3"> и
заполните ее следующим кодом<TabItem Header="Text3">
<FlowDocumentScrollViewer
ScrollViewer.VerticalScrollBarVisibility="Auto"
IsToolBarVisible="False"
>
<FlowDocument Background="White" FontSize="14">
<Paragraph TextAlignment="Center" FontWeight="Bold">
FlowDocument
<Italic>помещен в</Italic>
<Span Foreground="Red">FlowDocumentScrollViewer</Span>
</Paragraph>
<List MarkerStyle="None" FontFamily="Arial">
<ListItem>
<Paragraph>Буря мглою небо кроет</Paragraph>
</ListItem>
<ListItem>
<Paragraph>Вихри снежные крутя.</Paragraph>
</ListItem>
<ListItem>
<Paragraph>То как зверь она завоет</Paragraph>
</ListItem>
<ListItem>
<Paragraph>То заплачет как дитя.</Paragraph>
</ListItem>
</List>
<Paragraph TextAlignment="Left" FontSize="12">Текст
нефикированного формата FlowDocument нужно заключать в параграфы
(абзацы), внутри которых можно применять стилевые элементы.
</Paragraph>
<Paragraph>
<Bold>
<Span FontFamily="Comic Sans MS" FontSize="12" Foreground="Blue">
Буря мглою небо кроет вихри снежные крутя.
<LineBreak />
</Span>
</Bold>
То как зверь она завоет, то заплачет как дитя.
</Paragraph>
</FlowDocument>
</FlowDocumentScrollViewer>
</TabItem>
Присоединенный к дескриптору <FlowDocumentScrollViewer>
атрибут ScrollViewer.VerticalScrollBarVisibility="Auto" обеспечивает
автоматическое появление полосы прокрутки, если текст не помещается на
экране. Атрибуты, установленные в контейнере <FlowDocument>, действуют
по умолчанию на все дочерние элементы, если аналогичные атрибуты в них
не переопределены. В списках маркеры элементов можно менять или вообще
отключать.
Запустите приложение,
поизменяйте размер окна и разберитесь с кодомРезультат будет таким

Использование контейнера FlowDocumentPageViewer для FlowDocument позволяет
представлять документ как одну страницу без средства поиска текста и разбивки
его на страницы и колонки, но оставляет панель изменения масштаба и навигации.
Однако в самом FlowDocument есть свойства, позволяющие настраивать обычный
и многоколоночный текст. Вот некоторые из них
TextAlignment="Justify" - выравнивание текста по обеим границам
колонок (включен по умолчанию)IsHyphenationEnabled="True" - включение расстановки переносов (при наличии
словарей)IsOptimalParagraphEnabled="True" - включение оптимального абзаца, выравнивающего
пробелы между словами за счет разрежения символов в самих словах при режиме TextAlignment="Justify"ColumnGap="25" - ширина между колонками в логических пикселахColumnWidth="150" - предпочтительная (минимальная) ширина колонкиIsColumnWidthFlexible="False" - это значение флага явно запрещает дозаполнять
окно просмотра и устанавливает жесткую ширину колонкиColumnRuleWidth="5" - ширина вертикальных линеек, разделяющих колонки текстаColumnRuleBrush="Red" - цвет линеек
В контейнер <TabControl> добавьте
вкладку <TabItem Header="Text4"> и заполните ее следующим
кодом<TabItem Header="Text4">
<FlowDocumentPageViewer>
<FlowDocument
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="White"
ColumnWidth="150"
ColumnRuleWidth="2"
ColumnRuleBrush="Red"
ColumnGap="30"
IsHyphenationEnabled="True"
IsOptimalParagraphEnabled="True"
>
<Paragraph FontSize="18" FontWeight="Bold" TextAlignment="Center">
Примеры форматирования FlowDocument amp; FlowDocumentPageViewer
</Paragraph>
<Paragraph>
Это абзац с атрибутами по умолчанию.
</Paragraph>
<Paragraph>
Это еще один абзац с атрибутами по умолчанию.
</Paragraph>
<Paragraph FontSize="18">Абзац с FontSize="18"</Paragraph>
<Paragraph FontSize="15">Абзац с FontSize="15"</Paragraph>
<Paragraph FontSize="15">Список lt;List FontFamily="Arial"gt;</Paragraph>
<List FontFamily="Arial">
<ListItem>
<Paragraph>ListItem 1</Paragraph>
</ListItem>
<ListItem>
<Paragraph>ListItem 2</Paragraph>
</ListItem>
<ListItem>
<Paragraph>ListItem 3</Paragraph>
</ListItem>
<ListItem>
<Paragraph>ListItem 4</Paragraph>
</ListItem>
<ListItem>
<Paragraph>ListItem 5</Paragraph>
</ListItem>
</List>
<Paragraph>
<Bold>Это элемент lt;Boldgt; внутри абзаца lt;Paragraphgt;</Bold>
</Paragraph>
<Paragraph>
<Underline>Это элемент Underline внутри абзаца</Underline>
</Paragraph>
<Paragraph>
<Bold>
<Underline>Подчеркнутый внутри полужирного</Underline>
</Bold>
</Paragraph>
<Paragraph>
<Italic>Это элемент lt;Italicgt;</Italic>
</Paragraph>
<Paragraph>
<Span>Элемент Span с настройками по умолчанию</Span>
</Paragraph>
<Paragraph>
<Run>Элемент Run с настройками по умолчанию</Run>
</Paragraph>
<Paragraph FontSize="15">Subscript, Superscript</Paragraph>
<Paragraph>
<Run Typography.Variants="Superscript">This text is Superscripted.</Run>
This text isn't.
</Paragraph>
<Paragraph>
<Run Typography.Variants="Subscript">This text is Subscripted.</Run>
This text isn't.
</Paragraph>
<Paragraph TextIndent="-25" Margin="25,0">
If a font does not support a particular form (such as Superscript)
a default font form will be displayed.
</Paragraph>
<Paragraph FontSize="15">Blocks, breaks, paragraph</Paragraph>
<Section>
<Paragraph>A block section of text</Paragraph>
</Section>
<Section>
<Paragraph>Another block section of text</Paragraph>
</Section>
<Paragraph>
<LineBreak/>
</Paragraph>
<Section>
<Paragraph>... and another section, preceded by a LineBreak</Paragraph>
</Section>
<Section BreakPageBefore="True"/>
<Section>
<Paragraph>... and another section, preceded by a PageBreak</Paragraph>
</Section>
<Paragraph>Finally, a paragraph. Note the break between this paragraph ...</Paragraph>
<Paragraph TextIndent="25">... and this paragraph, and also the left indention.</Paragraph>
</FlowDocument>
</FlowDocumentPageViewer>
</TabItem>
Здесь мы применили основной набор элементов форматирования текста 'на лету'.
Обратите внимание, что в разметке угловые скобки кодируются как в HTML.
Другие управляющие символы разметки кодируются аналогично, например, ' '
кодируется как ' amp; '. Знак подчеркивания ' _ ' считается
служебным для выделения горячих клавиш в меню, поэтому в ином употреблении
должен экранироваться таким же знаком подчеркивания.
Параметры настройки FlowDocument разбивают текст
на колонки, задают ширину колонок, расстояние между ними и вертикальные линейки.
Определение пространств имен в дескрипторе FlowDocument здесь роли
не играет, но должно обязательно присутствовать для успокоения редактора,
если контейнер FlowDocument редактируется оболочкой автономно как внешний
файл документа.
Запустите приложение,
поизменяйте размер окна и разберитесь с кодомРезультат будет таким

Обратите внимание, что в длинных словах кириллический текст объект FlowDocument не переносит, а латиницу - переносит.
Проверьте действие
атрибута IsOptimalParagraphEnabled="True",
включающего оптимальный
параграфСледующий пример взят из MSDN (http://msdn.microsoft.com/ru-ru/library/system.windows.controls.flowdocumentscrollviewer.aspx)
и иллюстрирует дополнительные возможности разметки неформатированного текста
в FlowDocument. Он не содержит кириллицы, поэтому дальше нам пригодится
при решении проблем кодировки.
Добавьте новую вкладку
с приведенным кодом<TabItem Header="Text5" Selector.IsSelected="True">
<FlowDocumentScrollViewer Margin="10" BorderBrush="Black" BorderThickness="1">
<FlowDocument
ColumnWidth="400"
IsOptimalParagraphEnabled="True"
IsHyphenationEnabled="True"
>
<Section FontSize="12">
<Paragraph>
<Bold>Neptune</Bold> (planet), major planet in the solar system, eighth planet
from the Sun and fourth largest in diameter. Neptune maintains an almost constant
distance, about 4,490 million km (about 2,790 million mi), from the Sun. Neptune
revolves outside the orbit of Uranus and for most of its orbit moves inside the
elliptical path of the outermost planet Pluto (see Solar System). Every 248 years,
Pluto’s elliptical orbit brings the planet inside Neptune’s nearly circular orbit
for about 20 years, temporarily making Neptune the farthest planet from the Sun.
The last time Pluto’s orbit brought it inside Neptune’s orbit was in 1979. In
1999 Pluto’s orbit carried it back outside Neptune’s orbit.
<Figure
Width="140" Height="50" Background="GhostWhite"
HorizontalAnchor="PageLeft"
HorizontalOffset="100" VerticalOffset="20"
>
<Paragraph
FontStyle="Italic" TextAlignment="Left"
Background="Beige" Foreground="DarkGreen"
>
Neptune has 72 times Earth's volume...
</Paragraph>
</Figure>
<Floater
Background="GhostWhite"
Width="285" HorizontalAlignment="Left"
>
<Table CellSpacing="5">
<Table.Columns>
<TableColumn Width="155"/>
<TableColumn Width="130"/>
</Table.Columns>
<TableRowGroup>
<TableRow>
<TableCell ColumnSpan="3">
<Paragraph>Neptune Stats</Paragraph>
</TableCell>
</TableRow>
<TableRow Background="LightGoldenrodYellow" FontSize="12">
<TableCell>
<Paragraph FontWeight="Bold">Mean Distance from Sun</Paragraph>
</TableCell>
<TableCell>
<Paragraph>4,504,000,000 km</Paragraph>
</TableCell>
</TableRow>
<TableRow FontSize="12" Background="LightGray">
<TableCell>
<Paragraph FontWeight="Bold">Mean Diameter</Paragraph>
</TableCell>
<TableCell>
<Paragraph>49,532 km</Paragraph>
</TableCell>
</TableRow>
<TableRow Background="LightGoldenrodYellow" FontSize="12">
<TableCell>
<Paragraph FontWeight="Bold">Approximate Mass</Paragraph>
</TableCell>
<TableCell>
<Paragraph>1.0247e26 kg</Paragraph>
</TableCell>
</TableRow>
<TableRow>
<TableCell ColumnSpan="4">
<Paragraph FontSize="10" FontStyle="Italic">
Information from the
<Hyperlink
NavigateUri="http://encarta.msn.com/encnet/refpages/artcenter.aspx"
>
Encarta
</Hyperlink>
web site.
</Paragraph>
</TableCell>
</TableRow>
</TableRowGroup>
</Table>
</Floater>
</Paragraph>
<Paragraph>
Astronomers believe Neptune has an inner rocky core that is surrounded by a vast
ocean of water mixed with rocky material. From the inner core, this ocean extends
upward until it meets a gaseous atmosphere of hydrogen, helium, and trace amounts
of methane. Neptune has four rings and 11 known moons. Even though Neptune's volume
is 72 times Earth’s volume, its mass is only 17.15 times Earth’s mass. Because of
its size, scientists classify Neptune—along with Jupiter, Saturn, and Uranus—as
one of the giant or Jovian planets (so-called because they resemble Jupiter).
</Paragraph>
<Paragraph>
<Figure
Width="140" Height="50"
Background="GhostWhite" TextAlignment="Left"
HorizontalAnchor="PageCenter" WrapDirection="Both"
>
<Paragraph FontStyle="Italic" Background="Beige" Foreground="DarkGreen" >
Neptune has an orbital period of ~20 years...
</Paragraph>
</Figure>
Mathematical theories of astronomy led to the discovery of Neptune. To account for
wobbles in the orbit of the planet Uranus, British astronomer John Couch Adams and
French astronomer Urbain Jean Joseph Leverrier independently calculated the existence
and position of a new planet in 1845 and 1846, respectively. They theorized that the
gravitational attraction of this planet for Uranus was causing the wobbles in Uranus’s
orbit. Using information from Leverrier, German astronomer Johann Gottfried Galle first
observed the planet in 1846.
</Paragraph>
</Section>
</FlowDocument>
</FlowDocumentScrollViewer>
</TabItem>
Запустите приложение
- результат будет таким
Поизменяйте размер
окна и разберитесь с кодомОписание использованных в примере элементов можно найти на http://msdn.microsoft.com/ru-ru/library/system.windows.documents.aspx
Документ нефиксированного формата можно создать заранее в XAML -редакторе, сохранить его в файле и загружать во время выполнения в элемент управления просмотром. Продемонстрируем это на предыдущем примере.
Добавьте в разметку
новую вкладку следующего содержания (атрибут подписки на событие Initialized введите
вручную, чтобы правильно создать обработчик)<TabItem Header="Text6" Selector.IsSelected="True">
<FlowDocumentScrollViewer
Margin="10"
BorderBrush="Black"
BorderThickness="1"
Initialized="FlowDocumentScrollViewer_Initialized"
Name="documentReader" />
</TabItem>
Здесь мы декларативно определили и настроили пустой именованный контейнер
просмотра документа, а сам документ с содержимым FlowDocument загрузим из файла
программно и присоединим к свойству Document этого контейнера просмотра.
Уберите из предыдущей
вкладки атрибут Selector.IsSelected="True", чтобы при запуске приложения
сразу открывалась вкладка Text6
Добавьте к проекту WpfText2 новый XML -файл с именем XMLFile1.xml и измените его расширение c xml на xaml
Выделите новый файл
и измените через панель Properties его свойства на
Скопируйте из предыдущего
примера контейнер FlowDocument вместе с его содержимым в файл XMLFile1.xaml и добавьте атрибуты пространств имен WPF в дескриптор FlowDocumentМы создали, так называемый, свободный файл XAML. Свободный файл XAML - это файл со следующими характеристиками:
В нашем случае содержимое файла XMLFile1.xaml должно стать таким
<FlowDocument
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
ColumnWidth="400"
IsOptimalParagraphEnabled="True"
IsHyphenationEnabled="True"
>
<Section FontSize="12">
<Paragraph>
<Bold>Neptune</Bold> (planet), major planet in the solar system, eighth planet
from the Sun and fourth largest in diameter. Neptune maintains an almost constant
distance, about 4,490 million km (about 2,790 million mi), from the Sun. Neptune
revolves outside the orbit of Uranus and for most of its orbit moves inside the
elliptical path of the outermost planet Pluto (see Solar System). Every 248 years,
Pluto’s elliptical orbit brings the planet inside Neptune’s nearly circular orbit
for about 20 years, temporarily making Neptune the farthest planet from the Sun.
The last time Pluto’s orbit brought it inside Neptune’s orbit was in 1979. In
1999 Pluto’s orbit carried it back outside Neptune’s orbit.
<Figure
Width="140" Height="50" Background="GhostWhite"
HorizontalAnchor="PageLeft"
HorizontalOffset="100" VerticalOffset="20"
>
<Paragraph
FontStyle="Italic" TextAlignment="Left"
Background="Beige" Foreground="DarkGreen"
>
Neptune has 72 times Earth's volume...
</Paragraph>
</Figure>
<Floater
Background="GhostWhite"
Width="285" HorizontalAlignment="Left"
>
<Table CellSpacing="5">
<Table.Columns>
<TableColumn Width="155"/>
<TableColumn Width="130"/>
</Table.Columns>
<TableRowGroup>
<TableRow>
<TableCell ColumnSpan="3">
<Paragraph>Neptune Stats</Paragraph>
</TableCell>
</TableRow>
<TableRow Background="LightGoldenrodYellow" FontSize="12">
<TableCell>
<Paragraph FontWeight="Bold">Mean Distance from Sun</Paragraph>
</TableCell>
<TableCell>
<Paragraph>4,504,000,000 km</Paragraph>
</TableCell>
</TableRow>
<TableRow FontSize="12" Background="LightGray">
<TableCell>
<Paragraph FontWeight="Bold">Mean Diameter</Paragraph>
</TableCell>
<TableCell>
<Paragraph>49,532 km</Paragraph>
</TableCell>
</TableRow>
<TableRow Background="LightGoldenrodYellow" FontSize="12">
<TableCell>
<Paragraph FontWeight="Bold">Approximate Mass</Paragraph>
</TableCell>
<TableCell>
<Paragraph>1.0247e26 kg</Paragraph>
</TableCell>
</TableRow>
<TableRow>
<TableCell ColumnSpan="4">
<Paragraph FontSize="10" FontStyle="Italic">
Information from the
<Hyperlink
NavigateUri="http://encarta.msn.com/encnet/refpages/artcenter.aspx"
>
Encarta
</Hyperlink>
web site.
</Paragraph>
</TableCell>
</TableRow>
</TableRowGroup>
</Table>
</Floater>
</Paragraph>
<Paragraph>
Astronomers believe Neptune has an inner rocky core that is surrounded by a vast
ocean of water mixed with rocky material. From the inner core, this ocean extends
upward until it meets a gaseous atmosphere of hydrogen, helium, and trace amounts
of methane. Neptune has four rings and 11 known moons. Even though Neptune's volume
is 72 times Earth’s volume, its mass is only 17.15 times Earth’s mass. Because of
its size, scientists classify Neptune—along with Jupiter, Saturn, and Uranus—as
one of the giant or Jovian planets (so-called because they resemble Jupiter).
</Paragraph>
<Paragraph>
<Figure
Width="140" Height="50"
Background="GhostWhite" TextAlignment="Left"
HorizontalAnchor="PageCenter" WrapDirection="Both"
>
<Paragraph FontStyle="Italic" Background="Beige" Foreground="DarkGreen" >
Neptune has an orbital period of ~20 years...
</Paragraph>
</Figure>
Mathematical theories of astronomy led to the discovery of Neptune. To account for
wobbles in the orbit of the planet Uranus, British astronomer John Couch Adams and
French astronomer Urbain Jean Joseph Leverrier independently calculated the existence
and position of a new planet in 1845 and 1846, respectively. They theorized that the
gravitational attraction of this planet for Uranus was causing the wobbles in Uranus’s
orbit. Using information from Leverrier, German astronomer Johann Gottfried Galle first
observed the planet in 1846.
</Paragraph>
</Section>
</FlowDocument>
Заполните файл 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;
using System.IO;
namespace WpfText2
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void FlowDocumentScrollViewer_Initialized(object sender, EventArgs e)
{
documentReader.Document = (FlowDocument)XamlReader.
Load(File.OpenRead("XMLFile1.xaml"));
// Альтернативный вариант
//LoadFlowDocumentScrollViewerWithXAMLFile("XMLFile1.xaml");
}
// Альтернативный вариант
void LoadFlowDocumentScrollViewerWithXAMLFile(string fileName)
{
FileStream xamlFile = new FileStream(fileName, FileMode.Open, FileAccess.Read);
FlowDocument content = XamlReader.Load(xamlFile) as FlowDocument;
documentReader.Document = content;
xamlFile.Close();
}
}
}
Здесь мы свойству Document контейнера просмотра FlowDocumentScrollViewer присваиваем
возвращенный классом XamlReader размеченный
документ нефиксированного формата.
Запустите приложение
- получится точно такой же результат, как в предыдущем примере
Проверьте работу закомментированного
альтернативного варианта процедурного кодаПоскольку XAML -формат документов и сама технология WPF являются относительно
новыми, может потребоваться применить WPF к уже наработанному большому массиву HTML -документов. Для этого в WPF имеется класс System.Windows.Controls.WebBrowser.
Его не нужно путать с одноименным классом System.Windows.Forms.WebBrowser технологии Windows Forms. Описание WebBrowser приведено в
http://msdn.microsoft.com/ru-ru/library/system.windows.controls.webbrowser.aspx
В этом упражнении мы познакомимся с применением WebBrowser WPF к просмотру HTML -документов, а также с преобразованием HTML в рассмотренные ранее XAML -документы нефиксированного формата.
Добавьте к решению
командой File/Add/New Project новый проект WpfText3 типа WPF Application и
назначьте его стартовым
В декларативный раздел XAML добавьте контейнер <TabControl> с вкладкой <TabItem Header="HTML1">
Заполните файл Window1.xaml следующим кодом<Window x:Class="WpfText3.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1"
Height="300" Width="300"
Background="LightGray"
>
<TabControl>
<TabItem Header="HTML1">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<WebBrowser Grid.Row="0" Name="webBrowser1" />
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Center">
<Button Width="75" Content="Back" Click="backButton_Click" Margin="0,5,0,0" />
<Button Width="75" Content="Load" Click="loadButton_Click" Margin="5,5,5,0" />
<Button Width="75" Content="Forward" Click="forwardButton_Click" Margin="0,5,0,0" />
</StackPanel>
</Grid>
</TabItem>
</TabControl>
</Window>
Обработчики события Click кнопок заполните так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;
namespace WpfText3
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void loadButton_Click(object sender, RoutedEventArgs e)
{
Microsoft.Win32.OpenFileDialog openFileDialog = new Microsoft.Win32.OpenFileDialog();
openFileDialog.Filter = "HTML Documents (*.htm; *.html)|*.htm;*.html";
openFileDialog.InitialDirectory = System.IO.Directory.GetCurrentDirectory();
openFileDialog.Multiselect=false;
if (openFileDialog.ShowDialog() == false || openFileDialog.FileName == String.Empty)
return;
Uri uri = new Uri(openFileDialog.FileName);
this.webBrowser1.Source = uri;
}
private void backButton_Click(object sender, RoutedEventArgs e)
{
if (this.webBrowser1.CanGoBack)
{
this.webBrowser1.GoBack();
}
}
private void forwardButton_Click(object sender, RoutedEventArgs e)
{
if (this.webBrowser1.CanGoForward)
{
this.webBrowser1.GoForward();
}
}
}
}
Запустите проект -
получится нормальный инструмент просмотра HTML -документов
Обратите внимание, что в предыдущем примере автоматически появляются полосы
прокрутки, если HTML -документ не помещается в окне элемента WebBrowser. Фрагмент
форматированного HTML -текста включать прямо в WebBrowser нельзя, поскольку XAML -редактор оболочки сразу начнет ругаться. Но во время выполнения загружать
файл из кода можно.
В данном примере мы заранее создадим HTML -файл с простым форматированным текстом.
В Solution Explorer вызовите контекстное меню для узла WpfText3 и командой Add/Existing Item добавьте к проекту файл HtmlDoc.htm из прилагаемого каталога Source (или
создайте свой HTML -документ и добавьте его к проекту той же командой)Содержимое файла будет примерно таким
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Untitled Document</title>
<!--
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
-->
</head>
<body style="font-family:Arial, Helvetica, sans-serif">
<h2 align="center"><font color="#FF0000">Это небольшой фрагмент чистого HTML-текста</font></h2>
<ol>
<li>Шрифт Arial</li>
<li><font color="#0000FF">Цвет font color=quot;#0000FFquot;</font></li>
<li><font face="Courier New">Шрифт Courier New </font></li>
<li><b>Стиль полужирный lt;bgt; </b></li>
<li><i>Стиль Italic lt;igt; </i></li>
</ol>
</body>
</html>
Выделите этот файл
и в панели Properties настройте его свойства так
В декларативный раздел XAML в контейнер <TabControl> добавьте новую вкладку <TabItem Header="HTML2">
Заполните ее
следующим скриптом<TabItem Header="HTML2" Selector.IsSelected="True">
<WebBrowser x:Name="webBrowser2" Initialized="webBrowser2_Initialized" />
</TabItem>
Обработчик события Initialized заполните такprivate void webBrowser2_Initialized(object sender, EventArgs e)
{
Uri uri = new Uri(System.IO.Directory.GetCurrentDirectory() +
"\\HtmlDoc.htm", UriKind.Absolute);
this.webBrowser2.Navigate(uri);
}
Здесь мы применили несколько иной способ загрузки файла!
Запустите проект -
получится примерно следующее
Вертикальную полосу прокрутки мне убрать в этом примере не удалось.
Рассмотрим способ подключения HTML -текста из потока. В качестве источника текста будем использовать все тот же файл из предыдущего примера, полагая, что он будет находиться в одном каталоге со сборкой приложения в силу определенных нами ранее для него параметров.
В декларативный раздел XAML в контейнер <TabControl> добавьте новую вкладку <TabItem Header="HTML3">
Заполните ее следующим
скриптом<TabItem Header="HTML3" Selector.IsSelected="True">
<WebBrowser x:Name="webBrowser3" Initialized="webBrowser3_Initialized" />
</TabItem>
Обработчик события Initialized заполните такprivate void webBrowser3_Initialized(object sender, EventArgs e)
{
Uri uri = new Uri("HtmlDoc.htm", UriKind.Relative);
System.IO.Stream source = Application.GetRemoteStream(uri).Stream;
this.webBrowser3.NavigateToStream(source);
}
Запустите проект -
получится то же самое, что в предыдущем примере
В декларативный раздел XAML в контейнер <TabControl> добавьте новую вкладку <TabItem Header="HTML4">
Заполните ее следующим
скриптом<TabItem Header="HTML4" Selector.IsSelected="True">
<WebBrowser x:Name="webBrowser4" Initialized="webBrowser4_Initialized" />
</TabItem>
Обработчик события Initialized заполните такprivate void webBrowser4_Initialized(object sender, EventArgs e)
{
string path = System.IO.Directory.GetCurrentDirectory() + "\\HtmlDoc.htm";
System.IO.StreamReader streamReader = new System.IO.StreamReader(
path, Encoding.GetEncoding(1251));
//MessageBox.Show(streamReader.CurrentEncoding.CodePage.ToString());
string text = streamReader.ReadToEnd();
webBrowser4.NavigateToString(text);
}
Обязательно
закомментируйте или удалите HTML-дескриптор <meta> в документе HtmlDoc.htm, иначе будут проблемы с кодировкой "Кириллица
(Windows) - 1251" в
этом примере HTML4<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Untitled Document</title>
<!--
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
-->
</head>
<body style="font-family:Arial, Helvetica, sans-serif">
<h2 align="center"><font color="#FF0000">Это небольшой фрагмент чистого HTML-текста</font></h2>
<ol>
<li>Шрифт Arial</li>
<li><font color="#0000FF">Цвет font color=quot;#0000FFquot;</font></li>
<li><font face="Courier New">Шрифт Courier New </font></li>
<li><b>Стиль полужирный lt;bgt; </b></li>
<li><i>Стиль Italic lt;igt; </i></li>
</ol>
</body>
</html>
Запустите проект -
получится то же самое, что в предыдущем примере
Мы долго изучали инструменты WPF для работы с текстом нефиксированного формата и даже рассмотрели загрузку XAML -документа из файла. Но реально такие документы тяжело получить: либо их нужно 'загонять' вручную в WPF -проект, либо заранее готовить в отдельном файле. Это большая работа и для ее выполнения требуются определенные знания по пройденному нами материалу, в частности, о внутристрочных элементах.
Для заблаговременной подготовки текста существует наипростейший редактор XamlPad, который поставляется вместе
с оболочкой и его можно найти примерно в следующем месте компьютера (у меня
так, как показано, но я его положил еще и в папку Source ):
C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\XamlPad.exe
Фактически этот редактор проверяет синтаксис XAML -документа и чуток визуализирует его, но никак не автоматизирует работу по созданию.
К счастью, в настоящее время появились более развитые редакторы, которые интегрируются в оболочку или используются отдельно. Это Silverlight и Expression Blend - оба от компании Microsoft и оба платные.
Очень часто обычных возможностей по форматированию текста, используемых в HTML -редакторах, вполне достаточно, особенно для больших документов. Поэтому было бы желательно уметь преобразовывать текст HTML в XAML -документ. Встроенных библиотечных классов для решения этой задачи пока нет, зато есть сторонняя библиотека, автор которой - David Waddleton (http://blogs.msdn.com/DavidWaddleton). Проект этой библиотеки можно свободно загрузить по адресу:
http://waddleton.net/Documents/HtmlConversion.zip
Архив HtmlConversion.zip с проектом и
готовый файл HtmlConversion.dll библиотеки
приведены в прилагаемом каталоге Source. В данном упражнении мы воспользуемся
этой библиотекой 'вслепую', хотя никто не мешает познакомиться с исходным кодом,
распаковав архив с проектом.
Добавьте к решению
новый проект типа WPF Application с именем WpfText4 и
назначьте его стартовым
Для узла References проекта вызовите контекстное меню, вызовите окно Add Reference одноименной
командой и добавьте ссылку на библиотеку HtmlConversion.dll
В панели Solution
Explorer раскройте узел проекта WpfText3 и перетаскиванием мышью скопируйте файл HtmlDoc.htm в корневой узел текущего проекта WpfText4
В панели Properties проверьте, сохранились ли свойства HtmlDoc.htm
Декларативный раздел XAML заполните следующим
скриптом<Window x:Class="WpfText4.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1"
Height="300"
Width="300"
MinHeight="300"
MinWidth="300"
>
<FlowDocumentReader
Name="flowDocumentReader"
ViewingMode="Scroll"
HorizontalContentAlignment="Left"
IsPageViewEnabled="False"
IsPrintEnabled="False"
IsFindEnabled="False"
IsScrollViewEnabled="True"
IsTwoPageViewEnabled="False"
Zoom="75"
ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
Initialized="flowDocumentReader_Initialized"
/>
</Window>
Кодовую часть заполните
так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;
using System.Xml;
using System.IO;
using HTMLConverter;
namespace WpfText4
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void flowDocumentReader_Initialized(object sender, EventArgs e)
{
string path = Directory.GetCurrentDirectory() + "\\HtmlDoc.htm";
StreamReader streamReader = new StreamReader(
path, Encoding.GetEncoding("windows-1251"));
//MessageBox.Show(streamReader.CurrentEncoding.EncodingName);
string text = streamReader.ReadToEnd();
flowDocumentReader.Document = ConvertTextToFlowDocument(text);
}
public static FlowDocument ConvertTextToFlowDocument(string text)
{
try
{
string xaml = HTMLConverter.HtmlToXamlConverter.ConvertHtmlToXaml(text, true);
return XamlReader.Load(new XmlTextReader(new StringReader(xaml))) as FlowDocument;
}
catch (Exception)
{
return null;
}
}
}
}
Запустите проект -
получится почти то же самое, что в предыдущем упражнении
Хоть мы и не видели самого XAML -документа, но трудно отрицать, что в основном
он сформирован верно - вся разметка текста практически сохранилась. Для данного
примера мы произвольно применили элемент FlowDocumentReader, хотя могли выбрать
любой другой из ранее рассмотренных контейнеров.
Обратите
внимание, что для FlowDocumentReader установлено много декларативных
настроек. Стоит с ними поэкспериментировать, чтобы узнать получше, поскольку
эти настройки имеются у всех контейнеров документов нефиксированного формата FlowDocument.
Для больших документов преобразование на лету будет занимать время, да и все
прелести WPF пользователь не увидит. Разумнее заранее подготовить документы
в формате XAML, отредактировать их и уже готовыми подкачивать пользователю.
В этом упражнении мы этим и займемся, для чего опять воспользуемся библиотекой HtmlConversion.dll.
Добавьте к решению
новый проект WPF Application с именем WpfText5 и назначьте его стартовым
Добавьте к проекту
ссылку на библиотеку HtmlConversion.dll
Дескрипторная часть
проекта будет такой<Window x:Class="WpfText5.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1"
Height="300"
Width="300"
MinHeight="300"
MinWidth="300"
ResizeMode="CanResizeWithGrip"
>
<DockPanel Margin="3">
<StackPanel DockPanel.Dock="Bottom"
Orientation="Horizontal"
HorizontalAlignment="Center">
<Button Name="convertToXaml"
Width="85" Content="ConvertToXAML"
Click="convertToXaml_Click" />
<Button Name="loadXaml"
Width="85" Content="LoadXAML"
Margin="5,0,5,0"
Click="loadXaml_Click" />
<Button Name="editXaml"
Width="85"
Content="EditXAML"
Click="editXaml_Click" />
</StackPanel>
<FlowDocumentScrollViewer
x:Name="flowDocumentScrollViewer"
ScrollViewer.VerticalScrollBarVisibility="Visible"
Margin="0,0,0,3" >
<FlowDocument TextAlignment="Left">
<Paragraph TextAlignment="Center" FontWeight="Bold" FontSize="21">
Преобразование формата
</Paragraph>
<List MarkerStyle="Decimal" FontFamily="Arial" FontSize="14">
<ListItem>
<Paragraph>ConvertToXAML - выбрать HTML-файлы и
преобразовать в формат XAML
</Paragraph>
</ListItem>
<ListItem>
<Paragraph>LoadXAML - показать XAML-файл</Paragraph>
</ListItem>
<ListItem>
<Paragraph>EditXAML - редактировать файл в XAMLPad</Paragraph>
</ListItem>
</List>
</FlowDocument>
</FlowDocumentScrollViewer>
</DockPanel>
</Window>
На события Click кнопок
подпишитесь вручную, чтобы оболочка правильно создала обработчики
Кодовая часть проекта
будет такой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.IO;
using Microsoft.Win32;
using HTMLConverter;
using System.Windows.Markup;
namespace WpfText5
{
public partial class Window1 : Window
{
OpenFileDialog openFileDialog = new OpenFileDialog();
public Window1()
{
InitializeComponent();
}
// При конвертации создается подкаталог FilesXAML относительно текущего
private void convertToXaml_Click(object sender, RoutedEventArgs e)
{
openFileDialog.Title = "Select HTML-files";
openFileDialog.Filter = "HTML Documents (*.htm; *.html)|*.htm;*.html";
openFileDialog.Multiselect = true;
if (openFileDialog.ShowDialog() == false || openFileDialog.FileName == String.Empty)
return;
if (!Directory.Exists("FilesXAML"))
Directory.CreateDirectory("FilesXAML");
string[] fileNames = openFileDialog.FileNames;
foreach (String fileName in fileNames)
{
FileStream htmlStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
StreamReader myStreamReader = new StreamReader(htmlStream,
Encoding.GetEncoding(1251));
// Убираем полный путь и расширение
String name = fileName.Substring(0, fileName.LastIndexOf('.'));
int start = name.LastIndexOf('\\');
start = start != -1 ? start + 1 : 0;
name = name.Substring(start);
// Конвертируем
try
{
File.WriteAllText("FilesXAML\\" + name + ".xaml",
HtmlToXamlConverter.ConvertHtmlToXaml(myStreamReader.ReadToEnd(), true),
Encoding.GetEncoding(1251));
}
catch (Exception exc)
{
MessageBox.Show(exc.Message);
}
finally
{
// Сохранили информацию и закрыли потоки
htmlStream.Close();
myStreamReader.Close();
}
}
}
private void loadXaml_Click(object sender, RoutedEventArgs e)
{
openFileDialog.Title = "Select XAML-file";
openFileDialog.Filter = "XAML Documents (*.xaml)|*.xaml";
openFileDialog.Multiselect = false;
if (openFileDialog.ShowDialog() == false || openFileDialog.FileName == String.Empty)
return;
String fileName = openFileDialog.FileName;
try
{
FileStream htmlStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
StreamReader myStreamReader = new StreamReader(htmlStream,
Encoding.GetEncoding(1251));
FlowDocument content = XamlReader.Parse(myStreamReader.ReadToEnd()) as FlowDocument;
flowDocumentScrollViewer.Document = content;
}
catch { }
// Поток закрывать нельзя, разорвется связь с отображением документа
}
private void editXaml_Click(object sender, RoutedEventArgs e)
{
openFileDialog.Title = "Choose a folder with a XamlPad.exe";
openFileDialog.Filter = "XamlPad.exe|XamlPad.exe";
openFileDialog.RestoreDirectory = false;
if (openFileDialog.ShowDialog() == false || !File.Exists("XamlPad.exe"))
return;
String pathXamlPad = System.IO.Path.Combine(
Directory.GetCurrentDirectory(), "XamlPad.exe");
openFileDialog.Title = "Select XAML-file";
openFileDialog.Filter = "XAML Documents (*.xaml)|*.xaml";
openFileDialog.Multiselect = false;
if (openFileDialog.ShowDialog() == false || openFileDialog.FileName == String.Empty)
return;
System.Diagnostics.Process exe = new System.Diagnostics.Process();
exe.StartInfo.FileName = pathXamlPad; //Имя файла для запуска
exe.StartInfo.Arguments = openFileDialog.FileName; //Аргументы
try
{
exe.Start();
}
catch { }
}
}
}
Разберитесь с кодом,
испытайте приложение - в результате получился простой инструмент для преобразований HTML в XAML
Пара HTML -файлов с простой разметкой и готовых XAML -файлов приведена в каталоге Source, но вы можете попробовать конвертировать любой другой файл с не очень
сложной HTML -разметкой.
Конечно, это не промышленная программа Microsoft Silverlight или Microsoft Expression Blend, но элементарные преобразования она выполняет. И самое главное, - мы теперь немножко знаем, как и для чего это делается. Посмотрите, как неуклюже выглядит XamlPad, который находится в прилагаемом каталоге Source. Не удивляйтесь, что кириллицу он не отбражает, зато латиницу отображает прекрасно. В нем нет загрузки файлов, их следует указывать как параметр при запуске. И не нужно этому удивляться, ведь сделан-то он был фирмой Microsoft аж целых четыре года назад.
В данном упражнении приводится несколько примеров обработки текстовых файлов
и их форматирования в FlowDocument программным способом. Мне надоело описывать
пошаговые инструкции, а вам надоело их разбирать, поэтому приведу итоговый
код для исследования.
Что я сделал?
WPFText6 Documents и добавил в него готовый текстовый
файл TextDocument.txt с таким случайным содержимым (приводится в каталоге Source )Здесь знак подчеркивания '_' в начале параграфа является меткой для поиска в одном из примеров.
<Window x:Class="WpfText6.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1"
Height="300"
Width="300"
MinHeight="300"
MinWidth="300"
ResizeMode="CanResizeWithGrip"
Loaded="Window_Loaded"
>
<TabControl>
<TabItem Header="OneParagraph">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<FlowDocumentScrollViewer
DockPanel.Dock="Left"
x:Name="flowDocumentScrollViewer"
ScrollViewer.VerticalScrollBarVisibility="Visible"
>
<FlowDocument Name="flowDoc" TextAlignment="Left" Background="White">
<Paragraph TextAlignment="Center" FontWeight="Bold" FontSize="21">
Чтение одного параграфа
</Paragraph>
<Paragraph Name="text" FontFamily="Arial" />
</FlowDocument>
</FlowDocumentScrollViewer>
<ListBox Grid.Column="1" Name="listBox"
SelectionChanged="listBox_SelectionChanged" />
</Grid>
</TabItem>
<TabItem Header="FullDocument">
<FlowDocument Name="fullDocument" Loaded="fullDocument_Loaded" />
</TabItem>
<TabItem Header="SplitDocument">
<FlowDocumentScrollViewer ScrollViewer.VerticalScrollBarVisibility="Auto">
<FlowDocument Name="splitDocument"
Loaded="splitDocument_Loaded" Background="White" />
</FlowDocumentScrollViewer>
</TabItem>
<TabItem Header="ListDocument">
<FlowDocumentScrollViewer ScrollViewer.VerticalScrollBarVisibility="Auto">
<FlowDocument Name="listDocument"
Initialized="listDocument_Initialized" Background="White" />
</FlowDocumentScrollViewer>
</TabItem>
</TabControl>
</Window>
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.IO;
using Microsoft.Win32;
using System.Windows.Markup;
using System.Collections;
namespace WpfText6
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
// Вынесли как поля для видимости в методах
FileStream myStream;
StreamReader myStreamReader;
String[] arrayText;
private void Window_Loaded(object sender, RoutedEventArgs e)
{
this.Background = Brushes.LightGray;
// Можно вместо разделителя '\\' использовать '/'
String fileName = "Documents/TextDocument.txt";
try
{
myStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
myStreamReader = new StreamReader(myStream, Encoding.GetEncoding(1251));
// Не знаем, какой массив задать, поэтому читаем в коллекцию
// Но можно было и сразу в коллекцию StringBuilder.Append()
ArrayList arrayList = new ArrayList();
while (myStreamReader.EndOfStream != true)
arrayList.Add(myStreamReader.ReadLine());// Читаем построчно
// Копируем ссылки на элементы ArrayList в массив
arrayText = new String[arrayList.Count];
for (int i = 0; i < arrayList.Count; i++)
arrayText[i] = (String)arrayList[i];
// Заполняем ListBox
for (int i = 0; i < arrayText.Length; i++)
{
int pos = arrayText[i].IndexOf('.');
listBox.Items.Add(arrayText[i].Substring(0, pos + 1));
}
listBox.SelectedIndex = 0; // На первый элемент списка
}
catch { } // Один синтаксис!!!
finally
{
// Системные ресурсы надо закрывать
myStream.Close();
myStreamReader.Close();
}
}
private void listBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
text.Inlines.Clear(); // Очищаем предыдущее содержимое
text.Inlines.Add(arrayText[listBox.SelectedIndex]);// Добавляем новое
}
private void fullDocument_Loaded(object sender, RoutedEventArgs e)
{
fullDocument.Background = Brushes.White;// Фон документа программно
for (int i = 0; i < arrayText.Length; i++)
{
Paragraph para = new Paragraph();
para.FontFamily = new FontFamily("Arial");
para.Inlines.Add(arrayText[i]);
fullDocument.Blocks.Add(para);
}
}
String[] textSplit;
private void splitDocument_Loaded(object sender, RoutedEventArgs e)
{
// Можно вместо разделителя '\\' использовать '/'
String fileName = "Documents/TextDocument.txt";
try
{
myStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
myStreamReader = new StreamReader(myStream, Encoding.GetEncoding(1251));
String str = myStreamReader.ReadToEnd();// Читаем весь файл
textSplit = str.Split('_');// Расщепляем строку по метке '_'
// Элемент textSplit[0] получился пустой
}
catch (Exception) { } // Другой синтаксис!!!
finally
{
// Системные ресурсы надо закрывать
myStream.Close();
myStreamReader.Close();
}
// Формируем заголовок программно
Paragraph head = new Paragraph();
head.TextAlignment = TextAlignment.Center;
Run run = new Run("Документ получен расщеплением строки");
run.FontSize = 21;
Bold bold = new Bold(run);
head.Inlines.Add(bold);
splitDocument.Blocks.Add(head);
// Заполняем FlowDocument
splitDocument.FontFamily = new FontFamily("Arial");
for (int i = 1; i < textSplit.Length; i++)
{
Paragraph para = new Paragraph();
para.Inlines.Add(textSplit[i]);
splitDocument.Blocks.Add(para);
}
}
private void listDocument_Initialized(object sender, EventArgs e)
{
// Формируем заголовок
Paragraph head = new Paragraph();
head.TextAlignment = TextAlignment.Center;
Run run = new Run("Нумерованный список OrderList");
run.FontSize = 21;
Bold bold = new Bold(run);
head.Inlines.Add(bold);
listDocument.Blocks.Add(head);
// Создаем и настраиваем список
List list = new List();
list.MarkerOffset = 25;// Отступ от маркеров
list.MarkerStyle = TextMarkerStyle.Decimal;
list.StartIndex = 3; // Нумерация с 3
// Заполняем список дочерними элементами
list.ListItems.Add(new ListItem(new Paragraph(new Run("ListItem 1"))));
list.ListItems.Add(new ListItem(new Paragraph(new Run("ListItem 2"))));
list.ListItems.Add(new ListItem(new Paragraph(new Run("ListItem 3"))));
list.ListItems.Add(new ListItem(new Paragraph(new Run("ListItem 4"))));
list.ListItems.Add(new ListItem(new Paragraph(new Run("ListItem 5"))));
list.ListItems.Add(new ListItem(new Paragraph(new Run("ListItem 6"))));
list.ListItems.Add(new ListItem(new Paragraph(new Run("ListItem 7"))));
// Присоединяем список к документу
listDocument.FontFamily = new FontFamily("Arial");
listDocument.Blocks.Add(list);
}
}
}
Разберитесь с кодом,
или выкиньте мой и сочините свой, но чтобы все работало!Результаты по примерам будут такими:
![]() |
![]() |
![]() |
![]() |
Компьютерные технологии изменяются так стремительно, что некоторым студентам самое время подумать - не пересесть ли с компьютера за штурвал комбайна или не стать ли водителем кобылы. А что, Зелинский, это мысль! Будешь давать стране угля, и дров неналомаешь. Семью обеспечишь, да еще и звезду героя соцтруда могут дать. А у нас, программистов, - одни мозоли в голове, в карманах - вши на арканах, а у преподавателей от таких "студентов" - еще и головная боль впридачу!!! Отпусти нас, Зелинский!
Один из таких комбайнеров написал про меня в Интернете - молодой писака, писательский талант прорезался, на мемуары потянуло, распирать начало. Лучше бы почитывал пока, журналюга... Спасибо, хоть слова не переврал, и то благодаря все тому же Copy-Paste. Почитайте, вам будет поучительно, может станете больше прислушиваться к тому, что я постоянно говорю "Разберитесь с кодом":
http://blogs.mail.ru/mail/vitaliy2525/31E7226B44550EB4.html#
Пописывающий сетует, что что-то делал своими собственными ручками и все работало, но лень было в этом разбираться. А через несколько лет созрел и оказалось, что это красиво - вкусно - полезно. Так причем здесь Снетков?
"Окликнешь, тихо подойдешь, попросишь сторублевку... Причем здесь нож, причем грабеж? - меняй формулировку..." Высоцкий В.С.
Зреть нужно быстрее. Научить ПРОГРАММИРОВАТЬ можно только тех, кто сам этого хочет. Кода я привожу много, на любой вкус и цвет. Разбирайтесь, экспериментируйте, спрашивайте! Но не говорите, что все так плохо и только 'приколы' хороши - это непорядочно.
Высшее профессиональное образование - это не школа благородных девиц. И я не приставленный к ней надзиратель, а свободный преподаватель. Классики, и те уже попритихли. Как научить за мизерное количество часов (и зарплату...)? Заставлять покупать учебники по тысячу рублей штука? Так ведь редко же встречаются целиком стоющие - в одних одно, в других - другое, а большей частью - один хлам.
Взгляните, например, на этот, далеко не полный, ряд 'орудий пристрастья' современного программиста: C#, C++, MFC, VCL, .NET Framework, DirectX, OpenGL, XNA, ADO.NET, SQL, MySQL, SQL Server, Access, Crystal Reports, ASP.NET, HTML, XAML, XML, Windows Forms, WPF, PHP, Ajaxs, сами оболочки C++Builder и MS Visual Studio и т.д. А ведь все это - и есть объектно-ориентированное программирование! И сколько же тысяч нужно заплатить вашим родителям, если все это покупать, чтобы держать себя в форме?
Некоторые из вас и не заметили, что уже пощупали собственными ручками то, о чем ранее даже и не слышали. Все оплачено и налито, только пей. От ' такой методики ' еще никому не поплохело! Знаю, для 'непьющих' хватило бы и Бэйсика, или программирования на листочке, или сразу зачета? Так зачем тогда пришли и на какие средства в дальнейшем собираетесь жить, позвольте спросить, когда ваши родители состарятся и уйдут?
Я не программист, я их уже много лет только готовлю (с перцем, с луком, по собственному рецепту, на приспособах домашнего производства). Есть они не только в Красноярске, можно встретить в Новосибирске, Томске, Железногорске и т.д., и даже... - в Силиконовой долине. Моя ли в том вина, что иногда попадаются подпорченные продукты (я их сам не выбираю), или те, кто сел не в свои сани?
Когда я был маленький, у меня тоже была бабушка. Это было почти вчера, но время летит так быстро: где сейчас маленький, где эта бабушка... Имейте и вы это ввиду - не минет никого чаша сия и нужно все делать вовремя, чтобы успеть состояться в жизни, а не балду гонять! Так что - тужтесь сами, да посильнее, вам 'рожать'. А я на своем месте - стою на вспоможении... (хочешь - напрягайся, буду помогать! не хочешь - дело хозяйское)

Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.