带有按钮事件的dynamicresource的RichTextBox

时间:2013-07-08 10:04:05

标签: wpf events button richtextbox datatemplate

这里 我有一个扩展的richetextbox。你可以在datatemplate上找到动态绑定按钮的文本框, 当我点击删除按钮时,它无法正常工作。 帮助我在哪里出错。 这里是扩展的richetextbox文件。

        using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;

    namespace Rabbit.Controls
    {
       public  class RichTextBoxEx:RichTextBox
        {
               public bool AutoAddWhiteSpaceAfterTriggered
               {
                   get { return (bool)GetValue(AutoAddWhiteSpaceAfterTriggeredProperty); }
                   set { SetValue(AutoAddWhiteSpaceAfterTriggeredProperty, value); }
               }

               // Using a DependencyProperty as the backing store for AutoAddWhiteSpaceAfterTriggered.  This enables animation, styling, binding, etc...
               public static readonly DependencyProperty AutoAddWhiteSpaceAfterTriggeredProperty =
                   DependencyProperty.Register("AutoAddWhiteSpaceAfterTriggered", typeof(bool), typeof(RichTextBoxEx), new UIPropertyMetadata(true));

               public IList<String> ContentAssistSource
               {
                   get { return (IList<String>)GetValue(ContentAssistSourceProperty); }
                   set { SetValue(ContentAssistSourceProperty, value); }
               }

               // Using a DependencyProperty as the backing store for ContentAssistSource.  This enables animation, styling, binding, etc...
               public static readonly DependencyProperty ContentAssistSourceProperty =
                   DependencyProperty.Register("ContentAssistSource", typeof(IList<String>), typeof(RichTextBoxEx), new UIPropertyMetadata(new List<string>()));

               public IList<char> ContentAssistTriggers
               {
                   get { return (IList<char>)GetValue(ContentAssistTriggersProperty); }
                   set { SetValue(ContentAssistTriggersProperty, value); }
               }

               // Using a DependencyProperty as the backing store for ContentAssistSource.  This enables animation, styling, binding, etc...
               public static readonly DependencyProperty ContentAssistTriggersProperty =
                   DependencyProperty.Register("ContentAssistTriggers", typeof(IList<char>), typeof(RichTextBoxEx), new UIPropertyMetadata(new List<char>()));

               public static readonly DependencyProperty TokenTemplateProperty =
                   DependencyProperty.Register("TokenTemplate", typeof(DataTemplate), typeof(RichTextBoxEx));

               #region constructure
               public RichTextBoxEx()
               {
                   this.Loaded += new RoutedEventHandler(RichTextBoxEx_Loaded);
                   TextChanged += OnTokenTextChanged;
               }

               void RichTextBoxEx_Loaded(object sender, RoutedEventArgs e)
               {
                   //init the assist list box
                   if (this.Parent.GetType() != typeof(Grid))
                   {
                       throw new Exception("this control must be put in Grid control");
                   }

                   if (ContentAssistTriggers.Count == 0)
                   {
                       ContentAssistTriggers.Add('@');
                   }

                   (this.Parent as Grid).Children.Add(AssistListBox);
                   AssistListBox.MaxHeight = 100;
                   AssistListBox.MinWidth = 100;
                   AssistListBox.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
                   AssistListBox.VerticalAlignment = System.Windows.VerticalAlignment.Top;
                   AssistListBox.Visibility = System.Windows.Visibility.Collapsed;
                   AssistListBox.MouseDoubleClick += new MouseButtonEventHandler(AssistListBox_MouseDoubleClick);
                   AssistListBox.PreviewKeyDown += new KeyEventHandler(AssistListBox_PreviewKeyDown);
               }

               void AssistListBox_PreviewKeyDown(object sender, KeyEventArgs e)
               {
                   //if Enter\Tab\Space key is pressed, insert current selected item to richtextbox
                   if (e.Key == Key.Enter || e.Key == Key.Tab || e.Key == Key.Space)
                   {
                       InsertAssistWord();
                       OnTokenTextChanged(sender, null);
                       e.Handled = true;
                   }
                   else if (e.Key == Key.Back)
                   {
                       //Baskspace key is pressed, set focus to richtext box
                       if (sbLastWords.Length >= 1)
                       {
                           sbLastWords.Remove(sbLastWords.Length - 1, 1);
                       }
                       this.Focus();
                   }
               }

               void AssistListBox_MouseDoubleClick(object sender, MouseButtonEventArgs e)
               {
                   InsertAssistWord();
               }

               private bool InsertAssistWord()
               {
                   bool isInserted = false;
                   if (AssistListBox.SelectedIndex != -1)
                   {
                       string selectedString = AssistListBox.SelectedItem.ToString().Remove(0, sbLastWords.Length);
                       if (AutoAddWhiteSpaceAfterTriggered)
                       {
                           selectedString += ";";
                       }
                       this.InsertText(selectedString);
                       isInserted = true;
                   }

                   AssistListBox.Visibility = System.Windows.Visibility.Collapsed;
                   sbLastWords.Clear();
                   IsAssistKeyPressed = false;
                   return isInserted;
               }
               #endregion

               #region check richtextbox's document.blocks is available
               private void CheckMyDocumentAvailable()
               {
                   if (this.Document == null)
                   {
                       this.Document = new System.Windows.Documents.FlowDocument();
                   }
                   if (Document.Blocks.Count == 0)
                   {
                       Paragraph para = new Paragraph();
                       Document.Blocks.Add(para);
                   }
               }
               #endregion

               #region Insert Text
               public void InsertText(string text)
               {
                   Focus();
                   CaretPosition.InsertTextInRun(text);
                   TextPointer pointer = CaretPosition.GetPositionAtOffset(text.Length);
                   if (pointer != null)
                   {
                       CaretPosition = pointer;
                   }
               }
               #endregion

               #region Content Assist
               private bool IsAssistKeyPressed = false;
               private System.Text.StringBuilder sbLastWords = new System.Text.StringBuilder();
               private ListBox AssistListBox = new ListBox();

               protected override void OnPreviewKeyDown(System.Windows.Input.KeyEventArgs e)
               {
                   if (!IsAssistKeyPressed)
                   {
                       base.OnPreviewKeyDown(e);
                       return;
                   }

                   ResetAssistListBoxLocation();

                   if (e.Key == System.Windows.Input.Key.Back)
                   {
                       if (sbLastWords.Length > 0)
                       {
                           sbLastWords.Remove(sbLastWords.Length - 1, 1);
                           FilterAssistBoxItemsSource();
                       }
                       else
                       {
                           IsAssistKeyPressed = false;
                           sbLastWords.Clear();
                           AssistListBox.Visibility = System.Windows.Visibility.Collapsed;
                       }
                   }

                   //enter key pressed, insert the first item to richtextbox
                   if ((e.Key == Key.Enter || e.Key == Key.Space || e.Key == Key.Tab))
                   {
                       AssistListBox.SelectedIndex = 0;
                       if (InsertAssistWord())
                       {
                           e.Handled = true;
                       }
                   }

                   if (e.Key == Key.Down)
                   {
                       AssistListBox.Focus();
                   }

                   base.OnPreviewKeyDown(e);
               }

               private void FilterAssistBoxItemsSource()
               {
                   IEnumerable<string> temp = ContentAssistSource.Where(s => s.ToUpper().StartsWith(sbLastWords.ToString().ToUpper()));
                   AssistListBox.ItemsSource = temp;
                   AssistListBox.SelectedIndex = 0;
                   if (temp.Count() == 0)
                   {
                       AssistListBox.Visibility = System.Windows.Visibility.Collapsed;
                   }
                   else
                   {
                       AssistListBox.Visibility = System.Windows.Visibility.Visible;
                   }
               }

               protected override void OnTextInput(System.Windows.Input.TextCompositionEventArgs e)
               {
                   base.OnTextInput(e);
                   if (IsAssistKeyPressed == false && e.Text.Length == 1)
                   {
                       if (ContentAssistTriggers.Contains(char.Parse(e.Text)))
                       {
                           ResetAssistListBoxLocation();
                           IsAssistKeyPressed = true;
                           FilterAssistBoxItemsSource();
                           return;
                       }
                   }

                   if (IsAssistKeyPressed)
                   {
                       sbLastWords.Append(e.Text);
                       FilterAssistBoxItemsSource();
                   }
               }

               private void ResetAssistListBoxLocation()
               {
                   Rect rect = this.CaretPosition.GetCharacterRect(LogicalDirection.Forward);
                   double left = rect.X >= 20 ? rect.X : 20;
                   double top = rect.Y >= 20 ? rect.Y + 20 : 20;
                   left += this.Padding.Left;
                   top += this.Padding.Top;
                   AssistListBox.SetCurrentValue(ListBox.MarginProperty, new Thickness(left, top, 0, 0));
               }
               #endregion 

               public DataTemplate TokenTemplate
               {
                   get { return (DataTemplate)GetValue(TokenTemplateProperty); }
                   set { SetValue(TokenTemplateProperty, value); }
               }

               public Func<string, object> TokenMatcher { get; set; }

               private void OnTokenTextChanged(object sender, TextChangedEventArgs e)
               {
                   var text = CaretPosition.GetTextInRun(LogicalDirection.Backward);
                   if (TokenMatcher != null)
                   {
                       var token = TokenMatcher(text);
                       if (token != null)
                       {
                           ReplaceTextWithToken(text, token);
                       }
                   }
               }
               private void ReplaceTextWithToken(string inputText, object token)
               {
                   // Remove the handler temporarily as we will be modifying tokens below, causing more TextChanged events
                   TextChanged -= OnTokenTextChanged;

                   var para = CaretPosition.Paragraph;

                   var matchedRun = para.Inlines.FirstOrDefault(inline =>
                   {
                       var run = inline as Run;
                       return (run != null && run.Text.EndsWith(inputText));
                   }) as Run;
                   if (matchedRun != null) // Found a Run that matched the inputText
                   {
                       var tokenContainer = CreateTokenContainer(inputText, token);
                       para.Inlines.InsertBefore(matchedRun, tokenContainer);

                       // Remove only if the Text in the Run is the same as inputText, else split up
                       if (matchedRun.Text == inputText)
                       {
                           para.Inlines.Remove(matchedRun);
                       }
                       else // Split up
                       {
                           var index = matchedRun.Text.IndexOf(inputText) + inputText.Length;
                           var tailEnd = new Run(matchedRun.Text.Substring(index));
                           para.Inlines.InsertAfter(matchedRun, tailEnd);
                           para.Inlines.Remove(matchedRun);
                       }
                   }

                   TextChanged += OnTokenTextChanged;
               }
               private InlineUIContainer CreateTokenContainer(string inputText, object token)
               {
                   // Note: we are not using the inputText here, but could be used in future

                   var presenter = new ContentPresenter()
                   {
                       Content = token,
                       ContentTemplate = TokenTemplate,
                   };

                   // BaselineAlignment is needed to align with Run
                   return new InlineUIContainer(presenter) { BaselineAlignment = BaselineAlignment.TextBottom };
               }
        }
    }

这里是主窗口Xmal Code

    <Window x:Class="RichTextBoxWithIntellisense.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        mc:Ignorable="d"
        Title="Intellisense Rich Text Demo" Height="350" Width="525" xmlns:rabbit="clr-namespace:Rabbit.Controls;assembly=Rabbit.Controls">
     <Window.Resources>
        <LinearGradientBrush x:Key="ClickGradient">
            <GradientStop Color="#FF5C2014"/>
            <GradientStop Color="#FFB0452C"/>
        </LinearGradientBrush>
        <LinearGradientBrush x:Key="HoverGradient">
            <GradientStop Color="#FF757474"/>
            <GradientStop Color="#FF918F8F"/>
        </LinearGradientBrush>
        <!--<Style  x:Key="DeleteButton" TargetType="{x:Type Button}">
            <Setter Property="Template">
                <Setter.Value>-->
                    <ControlTemplate x:Key="CloseButton" TargetType="{x:Type Button}">
                            <Grid x:Name="MainGrid">
                                <Rectangle 
                                x:Name="MainRectangle" 
                                Fill="#00000000" 
                                RadiusX="5" 
                                RadiusY="5"/>
                                                <ContentPresenter 
                            x:Name="Presenter" 
                            HorizontalAlignment="Center" 
                            VerticalAlignment="Center" 
                            TextBlock.Foreground="#BB225588"/>
                                                <Path x:Name="Cross" Data="M0,0 L1,1 M0,1 L1,0" Stretch="Fill" 
                          Stroke="Black" StrokeThickness="2" Width="8" Height="8" />
                            </Grid>
                            <!--<StackPanel Orientation="Vertical">
                                <Path Width="16" Height="16" Fill="#FFFF0000" Stretch="Uniform" 
                                          Data="M19.85228,12.08996L12.093,19.849201 24.242323,31.997846 12.094,44.145998 19.852051,51.904958 32.001186,39.756277 44.150543,51.904958 51.909,44.145994 39.760246,31.997501 51.909,19.849201 44.15049,12.08996 32.001431,24.238849z M32,0C49.671021,3.1599484E-07 64,14.329407 64,31.998501 64,49.677606 49.671021,63.997003 32,63.997003 14.328003,63.997003 0,49.677606 0,31.998501 0,14.329407 14.328003,3.1599484E-07 32,0z">
                                </Path>
                            </StackPanel>-->
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter TargetName="MainRectangle" Property="Fill" Value="{StaticResource HoverGradient}"/>
                                <Setter TargetName="MainRectangle" Property="Stroke" Value="Transparent"/>
                                <Setter TargetName="Cross" Property="Stroke" Value="White" />
                            </Trigger>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter TargetName="MainRectangle" Property="Fill" Value="{StaticResource ClickGradient}"/>
                                <Setter TargetName="Cross" Property="Stroke" Value="White" />
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                <!--</Setter.Value>
            </Setter>
        </Style>-->
        <DataTemplate x:Key="NameTokenTemplate">
            <DataTemplate.Resources>
                    <Storyboard x:Key="OnLoaded1">
                        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="border">
                            <SplineDoubleKeyFrame KeyTime="0" Value="0"/>
                            <SplineDoubleKeyFrame KeyTime="0:0:0.5" Value="1"/>
                        </DoubleAnimationUsingKeyFrames>
                    </Storyboard>
                    <Style x:Key="BtnStyle" TargetType="{x:Type Button}">
                    <EventSetter Event="Click" Handler="Button_Click"/>
                </Style>
            </DataTemplate.Resources>
            <Border x:Name="border" BorderBrush="#FF7E7E7E" BorderThickness="2" CornerRadius="5" Height="Auto" d:DesignWidth="139" d:DesignHeight="40" Padding="5,3" Margin="3,0,3,3">
                <Border.Background>
                    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                        <GradientStop Color="White" Offset="0"/>
                        <GradientStop Color="LightGray" Offset="1"/>
                    </LinearGradientBrush>
                </Border.Background>
                <Grid HorizontalAlignment="Left" Width="Auto">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="0.79*"/>
                        <ColumnDefinition Width="0.21*"/>
                    </Grid.ColumnDefinitions>
                    <TextBlock TextWrapping="NoWrap" Grid.Column="0" Text="{Binding}" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="5,0,0,0" FontWeight="Bold"/>
                    <Button x:Name="DelBtn" Grid.Column="1" ClickMode="Press" Width="15" Visibility="Visible" HorizontalAlignment="Center" Margin="1" Padding="1,1.5,1,1.5"
                            Template="{StaticResource CloseButton}"
                            Style="{StaticResource BtnStyle}">
                        <Button.Content>
                            <Path x:Name="Cross" Data="M0,0 L1,1 M0,1 L1,0" Stretch="Fill" Stroke="Black" StrokeThickness="2" Width="8" Height="8" />
                        </Button.Content>
                    </Button>
                </Grid>
            </Border>
            <DataTemplate.Triggers>
                <EventTrigger RoutedEvent="FrameworkElement.Loaded">
                    <BeginStoryboard Storyboard="{StaticResource OnLoaded1}"/>
                </EventTrigger>
            </DataTemplate.Triggers>
        </DataTemplate>
    </Window.Resources>
    <Grid Margin="25">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <TextBlock Text="Try to type @ or . in the following rich text box:"/>
        <Grid Grid.Row="1">
            <rabbit:RichTextBoxEx   Name="richTextBoxEx1" TokenTemplate="{DynamicResource NameTokenTemplate}"
                           AutoAddWhiteSpaceAfterTriggered="{Binding IsChecked,ElementName=chkAutoAddWhitespace}" 
                           ContentAssistTriggers="{Binding ContentAssistTriggers}"
                           ContentAssistSource="{Binding ContentAssistSource}"/>
        </Grid>
        <CheckBox x:Name="chkAutoAddWhitespace" Grid.Row="2" Content="AutoAdd White Space After Trigger" IsChecked="True" />
    </Grid>
</Window>

这里是主窗口代码

    using System;
using System.Collections.Generic;
using System.Linq;
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 RichTextBoxWithIntellisense
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public List<String> ContentAssistSource
        {
            get { return (List<String>)GetValue(ContentAssistSourceProperty); }
            set { SetValue(ContentAssistSourceProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ContentAssisteSource.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ContentAssistSourceProperty =
            DependencyProperty.Register("ContentAssistSource", typeof(List<String>), typeof(MainWindow), new UIPropertyMetadata(new List<string>()));


        public List<char> ContentAssistTriggers
        {
            get { return (List<char>)GetValue(ContentAssistTriggersProperty); }
            set { SetValue(ContentAssistTriggersProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ContentAssistTriggers.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ContentAssistTriggersProperty =
            DependencyProperty.Register("ContentAssistTriggers", typeof(List<char>), typeof(MainWindow), new UIPropertyMetadata(new List<char>()));


        public MainWindow()
        {
            InitializeComponent();

            InitRichTextBoxSource();
            InitRichTextBoxIntellisenseTrigger();
            Loaded += delegate
            {
                richTextBoxEx1.Focus();
            };
            //richTextBoxEx1.Focus();
            DataContext = this;
            richTextBoxEx1.TokenMatcher = text =>
            {
                if (text.EndsWith(";"))
                {
                    // Remove the ';'
                    return text.Substring(0, text.Length - 1).Trim().ToUpper();
                }

                return null;
            };
        }

        private void InitRichTextBoxIntellisenseTrigger()
        {
            ContentAssistTriggers.Add('@');
            ContentAssistTriggers.Add('.');
        }

        private void InitRichTextBoxSource()
        {
            ContentAssistSource.Add("aaal");
            ContentAssistSource.Add("as");
            ContentAssistSource.Add("aacp");
            ContentAssistSource.Add("aid");
            ContentAssistSource.Add("asap");

            ContentAssistSource.Add("boy");
            ContentAssistSource.Add("big");
            ContentAssistSource.Add("before");
            ContentAssistSource.Add("belong");
            ContentAssistSource.Add("can");
            ContentAssistSource.Add("clever");
            ContentAssistSource.Add("cool");
            ContentAssistSource.Add("data");
            ContentAssistSource.Add("delete");
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            // Debug not comin here
        }

    }
}

1 个答案:

答案 0 :(得分:-1)

答案是将RichTextBox上的IsDocumentEnabled属性设置为true。