Posted by
Joseph on
1/10/2006 10:20 PM |
Comments (1)
To try to get “out of my comfort zone” (which is pretty small to begin with) in WPF I decided to try and emulate some of the UI enhancements I've heard about in Office 12. One of them is called “live preview” which shows you in real-time what potential changes (like increasing the font size, making something bold etc) will look like in your document as you you mouse over things. I implemented a “live preview” of the font changing. This was cool because I got to implement a font-selection dialog in WPF (creating a collection of system fonts and binding it to a dropdown list in WPF took about 5 lines of C# and 3 lines of XAML), and play with a few styles and such. In addition to this I had a look at manipulating the super-flexible WPF RichTextBox. I'm pretty sure if you didn't care about interoperability with MSWord you could build a fully-featured word processor using this control in a few days. One challenge was that none of the WPF UI elements provide a “hover” event (the font is only supposed to update if you hover over the same item for a little while). I had to fake it (poorly) using a timer. There are a few other glaring imperfections too - for example if you “preview” a font change but then don't actually select anything then your document DOESN'T go back to the way it was before...but hey - its a demo.

The reason the font dropdown list is so wide is because some of the names of the crazy fonts I installed to play around with this feature. There is a video of it in action also here [180 KB].
Here is the XAML (for the Dec 05 CTP):
<?Mapping XmlNamespace="urn:JCooney.Net.SeeingIsBelieving" ClrNamespace="SeeingIsBelieving" ?>
<Window x:Class="SeeingIsBelieving.Window1"
xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005"
xmlns:local="urn:JCooney.Net.SeeingIsBelieving"
Title="SeeingIsBelieving"
Loaded="mainWindowLoaded"
Width="450"
Height="200"
>
<Window.Resources>
<local:FontNameList x:Key="InstalledFonts"/>
<DataTemplate x:Key="FontComboTemplate">
<TextBlock Text="{Binding}" FontFamily="{Binding}" MouseEnter="fontSelectionMouseEnter"></TextBlock>
</DataTemplate>
<LinearGradientBrush x:Key="SelectedItemBackground" StartPoint="0,0" EndPoint="0,1">
<LinearGradientBrush.GradientStops>
<GradientStop Color="#e0e4ee" Offset="0.1"/>
<GradientStop Color="#c7d1e4" Offset="0.4"/>
<GradientStop Color="#acbbd9" Offset="0.5"/>
<GradientStop Color="#d5dcec" Offset="0.95"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="BorderThickness" Value="1" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{StaticResource SelectedItemBackground}"/>
<Setter Property="BorderBrush" Value="Blue"/>
<Setter Property="Foreground" Value="Black"/>
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter Property="Background" Value="{StaticResource SelectedItemBackground}"/>
<Setter Property="BorderBrush" Value="Blue"/>
<Setter Property="Foreground" Value="Black"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<DockPanel LastChildFill="True" >
<DockPanel LastChildFill="False" DockPanel.Dock="Top">
<ComboBox DockPanel.Dock="Right" x:Name="fontComboBox"
FontSize="20"
MouseLeave="fontComboMouseLeave"
SelectionChanged="fontComboSelectionChanged"
ItemsSource="{StaticResource InstalledFonts}"
ItemTemplate="{StaticResource FontComboTemplate}"/>
<TextBlock DockPanel.Dock="Right">Fonts:</TextBlock>
</DockPanel>
<Border BorderBrush="Navy" CornerRadius="5" BorderThickness="2">
<RichTextBox x:Name="testInput" AcceptsReturn="True" Padding="10,10,10,10" FontSize="20">
<FlowDocument>
<Paragraph>The quick brown fox jumps over the lazy dog.</Paragraph>
</FlowDocument>
</RichTextBox>
</Border>
</DockPanel>
</Window>
Here is the C# (also for the Dec 05 CTP)
using System;
using System.Drawing;
using System.Drawing.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace SeeingIsBelieving
{
///
/// Interaction logic for Window1.xaml
///
public partial class Window1 : Window
{
System.Windows.Threading.DispatcherTimer _hoverTimer = new System.Windows.Threading.DispatcherTimer();
string _fontFamilyName;
public Window1()
{
InitializeComponent();
}
void Window1_Loaded(object sender, RoutedEventArgs e)
{
}
private void mainWindowLoaded(object sender, RoutedEventArgs e)
{
_hoverTimer.Interval = new TimeSpan(0, 0, 0, 2);
_hoverTimer.Tick += new EventHandler(_hoverTimerTick);
}
void _hoverTimerTick(object sender, EventArgs e)
{
SetTextSelectionFont(_fontFamilyName);
}
private void SetTextSelectionFont(string fontFamilyName)
{
System.Windows.Media.FontFamily f = new System.Windows.Media.FontFamily(fontFamilyName);
testInput.Selection.ApplyPropertyValue(TextElement.FontFamilyProperty, f);
}
private void fontSelectionMouseEnter(object sender, RoutedEventArgs e)
{
TextBlock t = (TextBlock)sender;
_fontFamilyName = t.Text;
_hoverTimer.IsEnabled = false;
_hoverTimer.IsEnabled = true;
}
private void fontComboSelectionChanged(object sender, RoutedEventArgs e)
{
SetTextSelectionFont((string)fontComboBox.SelectedItem);
}
private void fontComboMouseLeave(object sender, RoutedEventArgs e)
{
_hoverTimer.IsEnabled = false;
}
}
public class FontNameList : System.Collections.Generic.List
{
public FontNameList()
{
using (InstalledFontCollection fonts = new InstalledFontCollection())
{
foreach (System.Drawing.FontFamily f in fonts.Families)
{
base.Add(f.Name);
}
}
}
}
}