Browse Source

added new control TokenizedTextBox. Not ready for use yet, still working on architecture and funtionality.

pull/1645/head
brianlagunas_cp 15 years ago
parent
commit
0499cd1b56
  1. 3
      ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Themes/Generic.xaml
  2. BIN
      ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/TokenizedTextBox/Images/delete8.png
  3. 20
      ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/TokenizedTextBox/Implementation/TokenItem.cs
  4. 276
      ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/TokenizedTextBox/Implementation/TokenizedTextBox.cs
  5. 14
      ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/TokenizedTextBox/Implementation/TokenizedTextBoxCommands.cs
  6. 59
      ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/TokenizedTextBox/Themes/Generic.xaml
  7. 10
      ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/WPFToolkit.Extended.csproj

3
ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Themes/Generic.xaml

@ -21,9 +21,8 @@
<ResourceDictionary Source="/WPFToolkit.Extended;component/SplitButton/Themes/Generic.xaml" /> <ResourceDictionary Source="/WPFToolkit.Extended;component/SplitButton/Themes/Generic.xaml" />
<ResourceDictionary Source="/WPFToolkit.Extended;component/PropertyGrid/Themes/Generic.xaml" /> <ResourceDictionary Source="/WPFToolkit.Extended;component/PropertyGrid/Themes/Generic.xaml" />
<ResourceDictionary Source="/WPFToolkit.Extended;component/TimePicker/Themes/Generic.xaml" /> <ResourceDictionary Source="/WPFToolkit.Extended;component/TimePicker/Themes/Generic.xaml" />
<ResourceDictionary Source="/WPFToolkit.Extended;component/TokenizedTextBox/Themes/Generic.xaml" />
<ResourceDictionary Source="/WPFToolkit.Extended;component/WatermarkTextBox/Themes/Generic.xaml" /> <ResourceDictionary Source="/WPFToolkit.Extended;component/WatermarkTextBox/Themes/Generic.xaml" />
<ResourceDictionary Source="/WPFToolkit.Extended;component/Wizard/Themes/Generic.xaml" /> <ResourceDictionary Source="/WPFToolkit.Extended;component/Wizard/Themes/Generic.xaml" />
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
</ResourceDictionary> </ResourceDictionary>

BIN
ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/TokenizedTextBox/Images/delete8.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 B

20
ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/TokenizedTextBox/Implementation/TokenItem.cs

@ -0,0 +1,20 @@
using System.Windows;
using System.Windows.Controls;
namespace Microsoft.Windows.Controls
{
public class TokenItem : ContentControl
{
static TokenItem()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(TokenItem), new FrameworkPropertyMetadata(typeof(TokenItem)));
}
public static readonly DependencyProperty TokenKeyProperty = DependencyProperty.Register("TokenKey", typeof(string), typeof(TokenItem), new UIPropertyMetadata(null));
public string TokenKey
{
get { return (string)GetValue(TokenKeyProperty); }
set { SetValue(TokenKeyProperty, value); }
}
}
}

276
ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/TokenizedTextBox/Implementation/TokenizedTextBox.cs

@ -0,0 +1,276 @@
//Based of the code written by Pavan Podila
//http://blog.pixelingene.com/2010/10/tokenizing-control-convert-text-to-tokens/
using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
namespace Microsoft.Windows.Controls
{
public class TokenizedTextBox : ItemsControl
{
#region Members
private System.Windows.Controls.RichTextBox _rtb = null;
private bool _surpressTextChanged = false;
private bool _surpressTextChangedEvent = false;
#endregion //Members
#region Properties
public static readonly DependencyProperty SearchMemberPathProperty = DependencyProperty.Register("SearchMemberPath", typeof(string), typeof(TokenizedTextBox), new UIPropertyMetadata(String.Empty));
public string SearchMemberPath
{
get { return (string)GetValue(SearchMemberPathProperty); }
set { SetValue(SearchMemberPathProperty, value); }
}
public static readonly DependencyProperty TokenDelimiterProperty = DependencyProperty.Register("TokenDelimiter", typeof(string), typeof(TokenizedTextBox), new UIPropertyMetadata(";"));
public string TokenDelimiter
{
get { return (string)GetValue(TokenDelimiterProperty); }
set { SetValue(TokenDelimiterProperty, value); }
}
public static readonly DependencyProperty TokenTemplateProperty = DependencyProperty.Register("TokenTemplate", typeof(DataTemplate), typeof(TokenizedTextBox), new UIPropertyMetadata(null));
public DataTemplate TokenTemplate
{
get { return (DataTemplate)GetValue(TokenTemplateProperty); }
set { SetValue(TokenTemplateProperty, value); }
}
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(TokenizedTextBox), new UIPropertyMetadata(null, OnTextChanged));
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
private static void OnTextChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
TokenizedTextBox tokenizedTextBox = o as TokenizedTextBox;
if (tokenizedTextBox != null)
tokenizedTextBox.OnTextChanged((string)e.OldValue, (string)e.NewValue);
}
protected virtual void OnTextChanged(string oldValue, string newValue)
{
if (_rtb == null || _surpressTextChanged)
return;
}
public static readonly DependencyProperty ValueMemberPathProperty = DependencyProperty.Register("ValueMemberPath", typeof(string), typeof(TokenizedTextBox), new UIPropertyMetadata(String.Empty));
public string ValueMemberPath
{
get { return (string)GetValue(ValueMemberPathProperty); }
set { SetValue(ValueMemberPathProperty, value); }
}
#endregion //Properties
#region Constructors
static TokenizedTextBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(TokenizedTextBox), new FrameworkPropertyMetadata(typeof(TokenizedTextBox)));
}
public TokenizedTextBox()
{
CommandBindings.Add(new CommandBinding(TokenizedTextBoxCommands.Delete, DeleteToken));
}
#endregion //Constructors
#region Base Class Overrides
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
if (_rtb != null)
_rtb.TextChanged -= OnTextChanged;
_rtb = GetTemplateChild("PART_ContentHost") as System.Windows.Controls.RichTextBox;
if (_rtb != null)
_rtb.TextChanged += OnTextChanged;
InitializeTokensFromText();
}
#endregion //Base Class Overrides
#region Event Handlers
private void OnTextChanged(object sender, TextChangedEventArgs e)
{
if (_surpressTextChangedEvent)
return;
var text = _rtb.CaretPosition.GetTextInRun(LogicalDirection.Backward);
var token = ResolveToken(text);
if (token != null)
{
ReplaceTextWithToken(text.Trim(), token);
}
}
#endregion //Event Handlers
#region Methods
private void InitializeTokensFromText()
{
if (!String.IsNullOrEmpty(Text))
{
string[] tokens = Text.Split(new string[] { TokenDelimiter }, StringSplitOptions.RemoveEmptyEntries);
foreach (string token in tokens)
{
var para = _rtb.CaretPosition.Paragraph;
para.Inlines.Add(CreateTokenContainer(String.Format("{0}{1}", token, TokenDelimiter), ResolveTokenFromItemsSource(token)));
}
}
}
private object ResolveToken(string text)
{
if (text.EndsWith(TokenDelimiter))
return ResolveTokenFromItemsSource(text.Substring(0, text.Length - 1).Trim());
return null;
}
private object ResolveTokenBySearchMemberPath(string searchText)
{
if (ItemsSource != null)
{
foreach (object item in ItemsSource)
{
var property = item.GetType().GetProperty(SearchMemberPath);
if (property != null)
{
var value = property.GetValue(item, null);
if (searchText.Equals(value.ToString(), StringComparison.InvariantCultureIgnoreCase))
{
return item;
}
}
}
}
return searchText;
}
private object ResolveTokenFromItemsSource(string tokenKey)
{
if (ItemsSource != null)
{
foreach (object item in ItemsSource)
{
var property = item.GetType().GetProperty(ValueMemberPath);
if (property != null)
{
var value = property.GetValue(item, null);
if (tokenKey.Equals(value.ToString(), StringComparison.InvariantCultureIgnoreCase))
return item;
}
}
}
return tokenKey;
}
private void ReplaceTextWithToken(string inputText, object token)
{
_surpressTextChangedEvent = true;
var para = _rtb.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);
}
//now append the Text
SetTextInternal(Text + inputText);
}
_surpressTextChangedEvent = false;
}
private InlineUIContainer CreateTokenContainer(string tokenKey, object token)
{
return new InlineUIContainer(CreateTokenItem(tokenKey, token)) { BaselineAlignment = BaselineAlignment.Center };
}
private TokenItem CreateTokenItem(string tokenKey, object token)
{
var tokenItem = new TokenItem();
tokenItem.TokenKey = tokenKey;
tokenItem.Content = token;
tokenItem.ContentTemplate = TokenTemplate;
if (TokenTemplate == null)
{
//if no template was supplied let's try to get a value from the object using the DisplayMemberPath
if (!String.IsNullOrEmpty(DisplayMemberPath))
{
var property = token.GetType().GetProperty(DisplayMemberPath);
if (property != null)
{
var value = property.GetValue(token, null);
if (value != null)
tokenItem.Content = value;
}
}
}
return tokenItem;
}
private void DeleteToken(object sender, ExecutedRoutedEventArgs e)
{
var para = _rtb.CaretPosition.Paragraph;
Inline inlineToRemove = para.Inlines.SingleOrDefault(x => ((x as InlineUIContainer).Child as TokenItem).TokenKey.Equals(e.Parameter));
if (inlineToRemove != null)
para.Inlines.Remove(inlineToRemove);
//update Text to remove delimited value
SetTextInternal(Text.Replace(e.Parameter.ToString(), ""));
}
private void SetTextInternal(string text)
{
_surpressTextChanged = true;
Text = text;
_surpressTextChanged = false;
}
#endregion //Methods
}
}

14
ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/TokenizedTextBox/Implementation/TokenizedTextBoxCommands.cs

@ -0,0 +1,14 @@
using System.Windows.Input;
namespace Microsoft.Windows.Controls
{
public static class TokenizedTextBoxCommands
{
private static RoutedCommand _deleteCommand = new RoutedCommand();
public static RoutedCommand Delete
{
get { return _deleteCommand; }
}
}
}

59
ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/TokenizedTextBox/Themes/Generic.xaml

@ -0,0 +1,59 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Microsoft.Windows.Controls" >
<Style TargetType="{x:Type local:TokenItem}">
<Setter Property="Background" Value="#F3F7FD" />
<Setter Property="BorderBrush" Value="#BBD8FB" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Cursor" Value="Arrow" />
<Setter Property="Padding" Value="5,1,5,1" />
<Setter Property="Margin" Value="1,0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:TokenItem}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}"
Margin="{TemplateBinding Margin}">
<StackPanel Orientation="Horizontal" Margin="1">
<ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" />
<Button Margin="3,0,0,0" Cursor="Hand" Command="local:TokenizedTextBoxCommands.Delete" CommandParameter="{TemplateBinding TokenKey}" >
<Button.Template>
<ControlTemplate TargetType="Button">
<ContentPresenter />
</ControlTemplate>
</Button.Template>
<Image Source="/WPFToolkit.Extended;component/TokenizedTextBox/Images/delete8.png" Width="8" Height="8" />
</Button>
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type local:TokenizedTextBox}" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:TokenizedTextBox}">
<Border x:Name="Bd" Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<RichTextBox x:Name="PART_ContentHost" AcceptsReturn="False" IsDocumentEnabled="True" Padding="-3,0,0,0" />
<!--<Popup>
<Grid Background="White">
<ItemsPresenter />
</Grid>
</Popup>-->
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

10
ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/WPFToolkit.Extended.csproj

@ -159,6 +159,10 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="TokenizedTextBox\Themes\Generic.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="WatermarkTextBox\Themes\Generic.xaml"> <Page Include="WatermarkTextBox\Themes\Generic.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
@ -291,6 +295,9 @@
<Compile Include="TimePicker\Implementation\TimeFormat.cs" /> <Compile Include="TimePicker\Implementation\TimeFormat.cs" />
<Compile Include="TimePicker\Implementation\TimeItem.cs" /> <Compile Include="TimePicker\Implementation\TimeItem.cs" />
<Compile Include="TimePicker\Implementation\TimePicker.cs" /> <Compile Include="TimePicker\Implementation\TimePicker.cs" />
<Compile Include="TokenizedTextBox\Implementation\TokenItem.cs" />
<Compile Include="TokenizedTextBox\Implementation\TokenizedTextBox.cs" />
<Compile Include="TokenizedTextBox\Implementation\TokenizedTextBoxCommands.cs" />
<Compile Include="VisualStates.cs" /> <Compile Include="VisualStates.cs" />
<Compile Include="MessageBox\Implementation\VisualStates.MessageBox.cs" /> <Compile Include="MessageBox\Implementation\VisualStates.MessageBox.cs" />
<Compile Include="WatermarkTextBox\Implementation\WatermarkTextBox.cs" /> <Compile Include="WatermarkTextBox\Implementation\WatermarkTextBox.cs" />
@ -376,6 +383,9 @@
<ItemGroup> <ItemGroup>
<Resource Include="MultiLineTextEditor\Images\Notes16.png" /> <Resource Include="MultiLineTextEditor\Images\Notes16.png" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Resource Include="TokenizedTextBox\Images\delete8.png" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

Loading…
Cancel
Save