【问题标题】:How can i add a delete button to delete token如何添加删除按钮来删除令牌
【发布时间】:2015-07-01 06:23:59
【问题描述】:

我正在尝试创建一个控件,它将接受我们在 stackoverflow 中使用的标记类型的功能。我正在尝试自定义 RichTextBox 以实现此功能。我已将以下链接作为参考。

http://blog.pixelingene.com/2010/10/tokenizing-control-convert-text-to-tokens/

如何添加删除按钮来删除令牌?

【问题讨论】:

    标签: wpf richtextbox token tokenize


    【解决方案1】:

    您可以通过向 DataTemplate 添加一个 Button 来实现上述功能。然后将 InLineUIContainer 分配给按钮的 Tag 属性。然后在按钮单击事件上,您可以从 RichTextBox 中删除 InLineUIContainer。 修改后的 DataTemplate 和 Tokenizer Control 代码参考以下代码。

    <Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:TokenizingControlTester" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="TokenizingControlTester.MainWindow"
        Title="Testing TokenizingControl" Height="244" Width="525" Icon="14-tag.png">
    <Window.Resources>
        <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>
            </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="#FFFFD0A0" Offset="0"/>
                        <GradientStop Color="#FFAB5600" Offset="1"/>
                    </LinearGradientBrush>
                </Border.Background>
                <Grid HorizontalAlignment="Left" Width="Auto">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="0.21*"/>
                        <ColumnDefinition Width="0.79*"/>
                        <ColumnDefinition Width="0.79*"/>
                    </Grid.ColumnDefinitions>
                    <Image HorizontalAlignment="Right" Source="14-tag.png" Stretch="None" Width="Auto" Grid.Column="0" VerticalAlignment="Center"/>
                    <TextBlock TextWrapping="NoWrap" Text="{Binding}" VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Column="1" Margin="10,0,0,0" FontWeight="Bold"/>
                    <Button Name="btnClose" Content="X" Grid.Column="2"  />
                </Grid>
            </Border>
            <DataTemplate.Triggers>
                <EventTrigger RoutedEvent="FrameworkElement.Loaded">
                    <BeginStoryboard Storyboard="{StaticResource OnLoaded1}"/>
                </EventTrigger>
            </DataTemplate.Triggers>
        </DataTemplate>
    </Window.Resources>
    <DockPanel>
        <DockPanel.Background>
            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                <GradientStop Color="#FFB8CCF7" Offset="0"/>
                <GradientStop Color="#FF313131" Offset="1"/>
            </LinearGradientBrush>
        </DockPanel.Background>
    
        <Grid DockPanel.Dock="Top" Margin="5,5,5,0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="0.059*"/>
                <ColumnDefinition Width="0.941*"/>
            </Grid.ColumnDefinitions>
            <Image Source="08-chat.png" Stretch="None" VerticalAlignment="Center" d:LayoutOverrides="Width"/>
    
            <TextBlock TextWrapping="Wrap" Text="Enter any text ending with semi-colon &quot;;&quot; and have it immediately converted to a Token" FontSize="16" d:LayoutOverrides="Width, Height" Grid.Column="1" Margin="7,0,0,0"/>
    
        </Grid>
    
        <local:TokenizingControl x:Name="Tokenizer"  IsDocumentEnabled="True"
                                 VerticalAlignment="Top" Margin="5,11,5,0" TokenTemplate="{DynamicResource NameTokenTemplate}" FontSize="16" MinHeight="40" VerticalScrollBarVisibility="Auto">
            <FlowDocument>
                <Paragraph><Run /></Paragraph>
            </FlowDocument>
        </local:TokenizingControl>
    
    </DockPanel>
    

     public class TokenizingControl : RichTextBox
    {
        public static readonly DependencyProperty TokenTemplateProperty =
            DependencyProperty.Register("TokenTemplate", typeof (DataTemplate), typeof (TokenizingControl));
    
        public DataTemplate TokenTemplate
        {
            get { return (DataTemplate) GetValue(TokenTemplateProperty); }
            set { SetValue(TokenTemplateProperty, value); }
        }
    
        public Func<string, object> TokenMatcher { get; set; }
    
        public TokenizingControl()
        {
            TextChanged += OnTokenTextChanged;
        }
    
        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 Dictionary<int, object> dic = new Dictionary<int, object>();
    
        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,
            };
            presenter.ApplyTemplate();
            Button bt = TokenTemplate.FindName("btnClose", presenter) as Button;
            bt.Click += bt_Click;
    
            InlineUIContainer inlin=  new InlineUIContainer(presenter) { BaselineAlignment = BaselineAlignment.TextBottom };
            bt.Tag = inlin;
            // BaselineAlignment is needed to align with Run
           return inlin;
        }
    
        void bt_Click(object sender, RoutedEventArgs e)
        {
            Button btn = sender as Button;
            InlineUIContainer inputText = btn.Tag as InlineUIContainer;
            Paragraph pr = null;
            foreach (var block in this.Document.Blocks)
            {
                if (block is Paragraph)
                {
                    var paragraph = block as Paragraph;
    
                    if(paragraph.Inlines.Contains(inputText))
                    {
                        pr = paragraph;
                    }
                }
            }
            pr.Inlines.Remove(inputText);           
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-01-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多