All the controls missing in WPF. Over 1 million downloads.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

220 lines
7.4 KiB

/************************************************************************
Extended WPF Toolkit
Copyright (C) 2010-2012 Xceed Software Inc.
This program is provided to you under the terms of the Microsoft Public
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
This program can be provided to you by Xceed Software Inc. under a
proprietary commercial license agreement for use in non-Open Source
projects. The commercial version of Extended WPF Toolkit also includes
priority technical support, commercial updates, and many additional
useful WPF controls if you license Xceed Business Suite for WPF.
Visit http://xceed.com and follow @datagrid on Twitter.
**********************************************************************/
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using Xceed.Wpf.Toolkit.Core;
namespace Xceed.Wpf.Toolkit
{
public class RichTextBoxFormatBarManager : DependencyObject
{
#region Members
private global::System.Windows.Controls.RichTextBox _richTextBox;
private UIElementAdorner<Control> _adorner;
private IRichTextBoxFormatBar _toolbar;
#endregion //Members
#region Properties
#region FormatBar
public static readonly DependencyProperty FormatBarProperty = DependencyProperty.RegisterAttached( "FormatBar", typeof( IRichTextBoxFormatBar ), typeof( RichTextBox ), new PropertyMetadata( null, OnFormatBarPropertyChanged ) );
public static void SetFormatBar( UIElement element, IRichTextBoxFormatBar value )
{
element.SetValue( FormatBarProperty, value );
}
public static IRichTextBoxFormatBar GetFormatBar( UIElement element )
{
return ( IRichTextBoxFormatBar )element.GetValue( FormatBarProperty );
}
private static void OnFormatBarPropertyChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
{
global::System.Windows.Controls.RichTextBox rtb = d as global::System.Windows.Controls.RichTextBox;
if( rtb == null )
throw new Exception( "A FormatBar can only be applied to a RichTextBox." );
RichTextBoxFormatBarManager manager = new RichTextBoxFormatBarManager();
manager.AttachFormatBarToRichtextBox( rtb, e.NewValue as IRichTextBoxFormatBar );
}
#endregion //FormatBar
public bool IsAdornerVisible
{
get
{
return _adorner.Visibility == Visibility.Visible;
}
}
#endregion //Properties
#region Event Handlers
void RichTextBox_MouseButtonUp( object sender, MouseButtonEventArgs e )
{
if( e.ChangedButton == MouseButton.Left && e.LeftButton == MouseButtonState.Released )
{
TextRange selectedText = new TextRange( _richTextBox.Selection.Start, _richTextBox.Selection.End );
#if !VS2008
if( selectedText.Text.Length > 0 && !String.IsNullOrWhiteSpace( selectedText.Text ) )
ShowAdorner();
#else
if( selectedText.Text.Length > 0 && !String.IsNullOrEmpty( selectedText.Text ) )
ShowAdorner();
#endif
else
HideAdorner();
e.Handled = true;
}
else
HideAdorner();
}
void RichTextBox_PreviewMouseMove( object sender, MouseEventArgs e )
{
//if the mouse moves outside the richtextbox bounds hide the adorner
//though this deosn't always work, especially if the user moves the mouse very quickly.
//need to find a better solution, but this will work for now.
Point p = e.GetPosition( _richTextBox );
if( p.X <= 5.0 || p.X >= _richTextBox.ActualWidth - 5 || p.Y <= 3.0 || p.Y >= _richTextBox.ActualHeight - 3 )
HideAdorner();
}
void RichTextBox_TextChanged( object sender, TextChangedEventArgs e )
{
//this fixes the bug when applying text transformations the text would lose it's highlight. That was because the RichTextBox was losing focus
//so we just give it focus again and it seems to do the trick of re-highlighting it.
if( !_richTextBox.IsFocused && !_richTextBox.Selection.IsEmpty )
_richTextBox.Focus();
}
#endregion //Event Handlers
#region Methods
/// <summary>
/// Attaches a FormatBar to a RichtextBox
/// </summary>
/// <param name="richTextBox">The RichtextBox to attach to.</param>
/// <param name="formatBar">The Formatbar to attach.</param>
private void AttachFormatBarToRichtextBox( global::System.Windows.Controls.RichTextBox richTextBox, IRichTextBoxFormatBar formatBar )
{
_richTextBox = richTextBox;
_richTextBox.PreviewMouseMove += RichTextBox_PreviewMouseMove;
//we cannot use the PreviewMouseLeftButtonUp event because of selection bugs.
//we cannot use the MouseLeftButtonUp event because it is handled by the RichTextBox and does not bubble up to here, so we must
//add a hander to the MouseUpEvent using the Addhandler syntax, and specify to listen for handled events too.
_richTextBox.AddHandler( Mouse.MouseUpEvent, new MouseButtonEventHandler( RichTextBox_MouseButtonUp ), true );
_richTextBox.TextChanged += RichTextBox_TextChanged;
_adorner = new UIElementAdorner<Control>( _richTextBox );
formatBar.Target = _richTextBox;
_toolbar = formatBar;
}
/// <summary>
/// Shows the FormatBar
/// </summary>
void ShowAdorner()
{
if( _adorner.Visibility == Visibility.Visible )
return;
VerifyAdornerLayer();
_toolbar.Update();
Control adorningEditor = _toolbar as Control;
if( _adorner.Child == null )
_adorner.Child = adorningEditor;
_adorner.Visibility = Visibility.Visible;
PositionFormatBar( adorningEditor );
}
/// <summary>
/// Positions the FormatBar so that is does not go outside the bounds of the RichTextBox or covers the selected text
/// </summary>
/// <param name="adorningEditor"></param>
private void PositionFormatBar( Control adorningEditor )
{
Point mousePosition = Mouse.GetPosition( _richTextBox );
double left = mousePosition.X;
double top = ( mousePosition.Y - 15 ) - adorningEditor.ActualHeight;
//top
if( top < 0 )
{
top = mousePosition.Y + 10;
}
//right boundary
if( left + adorningEditor.ActualWidth > _richTextBox.ActualWidth - 20 )
{
left = left - ( adorningEditor.ActualWidth - ( _richTextBox.ActualWidth - left ) );
}
_adorner.SetOffsets( left, top );
}
/// <summary>
/// Ensures that the IRichTextFormatBar is in the adorner layer.
/// </summary>
/// <returns>True if the IRichTextFormatBar is in the adorner layer, else false.</returns>
bool VerifyAdornerLayer()
{
if( _adorner.Parent != null )
return true;
AdornerLayer layer = AdornerLayer.GetAdornerLayer( _richTextBox );
if( layer == null )
return false;
layer.Add( _adorner );
return true;
}
/// <summary>
/// Hides the IRichTextFormatBar that is in the adornor layer.
/// </summary>
void HideAdorner()
{
if( IsAdornerVisible )
{
_adorner.Visibility = Visibility.Collapsed;
//_adorner.Child = null;
}
}
#endregion //Methods
}
}