This example creates a custom token editor (CustomTokenEdit
) that displays a checkbox in tokens.
You can use the custom token editor as a standalone editor or as a cell editor in data-aware controls (for example, Data Grid, TreeList).
Tokens are of the CustomTokenEditToken
type. This class inherits base functionality from the TokenEditToken class and introduces a new Checked
property. When the checked state of a token changes, the editor raises the RepositoryItemCustomTokenEdit.TokenCheckedChanged
event.
Files to Review
- CustomTokenEdit.cs
- CustomTokenEditCheckedItemCollection.cs
- CustomTokenEdithandler.cs
- CustomTokenEditHitInfo.cs
- CustomTokenEditPainter.cs
- CustomTokenEditSelectedItemCollection.cs
- CustomTokenEditToken.cs
- CustomTokenEditTokenInfo.cs
- CustomTokenEditViewInfo.cs
- RepositoryItemCustomTokenEdit.cs
- TokenCheckedChangedEventArgs.cs
- Form1.cs
See Also
Does this example address your development requirements/objectives?
(you will be redirected to DevExpress.com to submit your response)
Example Code
C#using DevExpress.XtraEditors;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
namespace TokenEdit_Glyph_InEndOfToken.CustomTokenEdit
{
[ToolboxItem(true)]
public class CustomTokenEdit : TokenEdit
{
static CustomTokenEdit()
{
RepositoryItemCustomTokenEdit.Register();
}
public CustomTokenEdit()
{
(Painter as CustomTokenEditPainter).SetEditor(this);
}
public override string EditorTypeName
{
get { return RepositoryItemCustomTokenEdit.EditorName; }
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public new RepositoryItemCustomTokenEdit Properties
{
get { return base.Properties as RepositoryItemCustomTokenEdit; }
}
public void Repaint()
{
base.LayoutChanged();
}
protected override TokenEditHandler CreateHandler()
{
return new CustomTokenEdithandler(this);
}
public CustomTokenEditToken CheckedItem { get { return base.CheckedItem as CustomTokenEditToken;} }
public CustomTokenEditCheckedItemCollection CheckedItems { get { return base.CheckedItems as CustomTokenEditCheckedItemCollection; } }
public CustomTokenEditSelectedItemCollection SelectedItems { get { return base.SelectedItems as CustomTokenEditSelectedItemCollection; } }
}
}
C#using DevExpress.XtraEditors;
using System;
using System.Collections.Generic;
using System.Linq;
using DevExpress.XtraEditors.Repository;
namespace TokenEdit_Glyph_InEndOfToken.CustomTokenEdit
{
public class CustomTokenEditCheckedItemCollection : TokenEditCheckedItemCollection
{
public CustomTokenEditCheckedItemCollection(RepositoryItemTokenEdit properties)
: base(properties) { }
public CustomTokenEditToken this[int index] { get { return (CustomTokenEditToken)InnerList[index]; } }
}
}
C#using DevExpress.XtraEditors;
using DevExpress.XtraEditors.ViewInfo;
using System;
using System.Collections.Generic;
using System.Linq;
namespace TokenEdit_Glyph_InEndOfToken.CustomTokenEdit
{
public class CustomTokenEdithandler : TokenEditHandler
{
public CustomTokenEdithandler(TokenEdit tokenEdit) : base(tokenEdit) { }
protected override void OnTokenClick(TokenEditHitInfo hitInfo)
{
ChangeCheckedIfRequired(hitInfo);
base.OnTokenClick(hitInfo);
}
private void ChangeCheckedIfRequired(TokenEditHitInfo hitInfo)
{
CustomTokenEditHitInfo hInfo = hitInfo as CustomTokenEditHitInfo;
if (hInfo.IsInCheckBox)
(hitInfo.HitObject as CustomTokenEditTokenInfo).ChangeChecked();
}
}
}
C#using DevExpress.XtraEditors.ViewInfo;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Drawing;
namespace TokenEdit_Glyph_InEndOfToken.CustomTokenEdit
{
public class CustomTokenEditHitInfo : TokenEditHitInfo
{
public CustomTokenEditHitInfo() { }
public CustomTokenEditHitInfo(Point pt) : base(pt) { }
public void ResetHitTest(TokenEditHitTest ht )
{
SetHitTest(ht);
}
public void ResetHitObject(TokenEditTokenInfo obj)
{
SetHitObject(obj);
}
public bool IsInCheckBox { get; private set; }
public void InCheckBox(bool val)
{
IsInCheckBox = val;
}
}
}
C#using DevExpress.Skins;
using DevExpress.Utils;
using DevExpress.Utils.Drawing;
using DevExpress.XtraEditors;
using DevExpress.XtraEditors.Drawing;
using DevExpress.XtraEditors.ViewInfo;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
namespace TokenEdit_Glyph_InEndOfToken.CustomTokenEdit {
public class CustomTokenEditPainter : TokenEditPainter {
CustomTokenEdit editor;
public void SetEditor(CustomTokenEdit _editor) {
editor = _editor;
}
protected override void DoDrawGlyph(ControlGraphicsInfoArgs info, TokenEditTokenInfo tokenInfo) {
base.DoDrawGlyph(info, tokenInfo);
if (editor.Properties.CheckBoxSkinElement != null) {
int index = 0;
CustomTokenEditTokenInfo customTokenInfo = tokenInfo as CustomTokenEditTokenInfo;
int offset = customTokenInfo.Checked == true ? 4 : 0;
Rectangle rect = customTokenInfo.CheckBoxGlyphBounds;
Rectangle r = new Rectangle(rect.X + (int)info.Graphics.ClipBounds.X, rect.Y + (int)info.Graphics.ClipBounds.Y, rect.Width, rect.Height);
SkinElementInfo skinElementInfo = new SkinElementInfo(editor.Properties.CheckBoxSkinElement, r);
switch (customTokenInfo.CheckBoxState) {
case ObjectState.Normal:
index = offset;
break;
case ObjectState.Hot:
index = offset + 1;
break;
case ObjectState.Hot | ObjectState.Pressed:
index = offset + 2;
break;
}
skinElementInfo.ImageIndex = index;
ImageCollection imageCollection = editor.Properties.CheckBoxSkinElement.Image.GetImages();
info.Graphics.DrawImage(imageCollection.Images[index], new Rectangle(rect.X + (int)info.Graphics.ClipBounds.X, rect.Y + (int)info.Graphics.ClipBounds.Y, rect.Width, rect.Height));
ObjectPainter.DrawObject(info.Cache, SkinElementPainter.Default, skinElementInfo);
}
}
}
}
C#using DevExpress.XtraEditors;
using System;
using System.Collections.Generic;
using System.Linq;
using DevExpress.XtraEditors.Repository;
namespace TokenEdit_Glyph_InEndOfToken.CustomTokenEdit {
public class CustomTokenEditSelectedItemCollection : TokenEditSelectedItemCollection {
public CustomTokenEditSelectedItemCollection(RepositoryItemTokenEdit properties) : base(properties) { }
public CustomTokenEditToken this[int index] { get { return (CustomTokenEditToken)InnerList[index]; } }
}
}
C#using DevExpress.XtraEditors;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TokenEdit_Glyph_InEndOfToken.CustomTokenEdit
{
public class CustomTokenEditToken : TokenEditToken
{
public CustomTokenEditToken() { }
public CustomTokenEditToken(object value) : base(value) { }
public CustomTokenEditToken(string description, object value, RepositoryItemCustomTokenEdit _Properties)
: base(description, value) { Properties = _Properties; }
readonly RepositoryItemCustomTokenEdit Properties;
protected bool _checked;
protected internal bool needRepaint = true;
public bool Checked
{
get { return _checked; }
set
{
if (_checked != value)
{
_checked = value;
OnCheckedChanged();
}
}
}
void OnCheckedChanged()
{
Properties.OnTokenCheckedChanged(this, needRepaint);
needRepaint = true;
}
}
}
C#using DevExpress.XtraEditors.ViewInfo;
using System;
using System.Collections.Generic;
using System.Linq;
using DevExpress.XtraEditors;
using System.Drawing;
using DevExpress.Utils.Drawing;
namespace TokenEdit_Glyph_InEndOfToken.CustomTokenEdit
{
public class CustomTokenEditTokenInfo : TokenEditTokenInfo
{
public CustomTokenEditTokenInfo(TokenEditToken token) : base(token) { }
public CustomTokenEditTokenInfo(TokenEditToken token, Dictionary<TokenEditToken, Rectangle> _checkBoxBounds, CustomTokenEditViewInfo _viewInfo) : base(token)
{
checkBoxBounds = _checkBoxBounds;
viewInfo = _viewInfo;
}
public CustomTokenEditToken CustomToken { get { return base.Token as CustomTokenEditToken; } }
readonly Dictionary<TokenEditToken, Rectangle> checkBoxBounds;
public Rectangle CheckBoxGlyphBounds { get { return checkBoxBounds[CustomToken]; } }
readonly CustomTokenEditViewInfo viewInfo;
public bool Checked { get { return CustomToken.Checked; } }
public void ChangeChecked()
{
CustomToken.needRepaint = false;
CustomToken.Checked = !CustomToken.Checked;
}
ObjectState checkBoxState;
public ObjectState CheckBoxState
{
get
{
return checkBoxState;
}
set
{
if (checkBoxState != value)
{
checkBoxState = value;
OnCheckBoxStateChanged();
}
}
}
void OnCheckBoxStateChanged()
{
viewInfo.InvalidateCheckBox();
}
}
}
C#using DevExpress.XtraEditors.ViewInfo;
using System;
using System.Collections.Generic;
using System.Linq;
using DevExpress.XtraEditors.Repository;
using System.Drawing;
using DevExpress.Utils.Drawing;
using System.Windows.Forms;
using DevExpress.XtraEditors;
namespace TokenEdit_Glyph_InEndOfToken.CustomTokenEdit
{
public class CustomTokenEditViewInfo : TokenEditViewInfo
{
public CustomTokenEditViewInfo(RepositoryItem item) : base(item)
{
checkBoxBounds = new Dictionary<TokenEditToken, Rectangle>();
}
readonly Dictionary<TokenEditToken, Rectangle> checkBoxBounds;
protected override Rectangle CalcBounds(Point topPt, TokenEditToken token)
{
Rectangle rect = base.CalcBounds(topPt, token);
Rectangle temp = CalcGlyphBounds(token, rect);
checkBoxBounds[token] = new Rectangle(rect.Right, temp.Top, temp.Width, temp.Height);
rect.Width += CalcGlyphWidth(token) + ItemContentMargin;
return rect;
}
protected override void UpdateTokenState(TokenEditTokenInfo tokenInfo)
{
base.UpdateTokenState(tokenInfo);
if (!Item.ReadOnly)
{
Point pt = OwnerControl != null ? OwnerControl.PointToClient(Control.MousePosition) : MousePosition;
CustomTokenEditTokenInfo info = tokenInfo as CustomTokenEditTokenInfo;
if (info.CheckBoxGlyphBounds.Contains(pt))
{
info.CheckBoxState = ObjectState.Hot;
if ((Control.MouseButtons & MouseButtons.Left) != 0) info.CheckBoxState |= ObjectState.Pressed;
}
else
{
info.CheckBoxState = ObjectState.Normal;
}
}
}
protected internal void InvalidateCheckBox()
{
DoInvalidate();
}
protected override TokenEditTokenInfo CreateTokenEditTokenInfo(TokenEditToken token)
{
CustomTokenEditTokenInfo info = new CustomTokenEditTokenInfo(token, checkBoxBounds, this);
return info;
}
protected override EditHitInfo CreateHitInfo(Point p)
{
return new CustomTokenEditHitInfo(p);
}
public override EditHitInfo CalcHitInfo(Point pt)
{
CustomTokenEditHitInfo hi = CreateHitInfo(pt) as CustomTokenEditHitInfo;
if(!Bounds.Contains(pt)) return hi;
foreach(CustomTokenEditTokenInfo tokenInfo in VisibleItems)
{
if(tokenInfo.Bounds.Contains(pt))
{
hi.ResetHitObject(tokenInfo);
hi.ResetHitTest(TokenEditHitTest.Link);
hi.InCheckBox(false);
if (tokenInfo.CheckBoxGlyphBounds.Contains(pt)) hi.InCheckBox(true);
if(tokenInfo.GlyphBounds.Contains(pt)) hi.ResetHitTest(TokenEditHitTest.Glyph);
return hi;
}
}
if(ContentRect.Contains(pt)) hi.ResetHitTest(TokenEditHitTest.EditorRect);
return hi;
}
}
}
C#using DevExpress.Skins;
using DevExpress.Utils;
using DevExpress.XtraEditors;
using DevExpress.XtraEditors.Registrator;
using DevExpress.XtraEditors.Repository;
using System;
using System.Collections.Generic;
using System.Linq;
namespace TokenEdit_Glyph_InEndOfToken.CustomTokenEdit {
[UserRepositoryItem("Register")]
public class RepositoryItemCustomTokenEdit : RepositoryItemTokenEdit {
static RepositoryItemCustomTokenEdit() { Register(); }
public RepositoryItemCustomTokenEdit() { checkBoxCollection = GetCheckBoxImages(); }
internal const string EditorName = "CustomTokenEdit";
public static void Register() {
EditorRegistrationInfo.Default.Editors.Add(new EditorClassInfo(EditorName, typeof(CustomTokenEdit),
typeof(RepositoryItemCustomTokenEdit), typeof(CustomTokenEditViewInfo),
new CustomTokenEditPainter(), true, null));
}
public override string EditorTypeName { get { return EditorName; } }
readonly SkinElement checkBoxCollection;
public SkinElement CheckBoxSkinElement { get { return checkBoxCollection; } }
protected virtual SkinElement GetCheckBoxImages() {
Skin skin = EditorsSkins.GetSkin(DevExpress.LookAndFeel.UserLookAndFeel.Default);
SkinElement skinElement = skin["CheckBox"];
if (skinElement == null)
return null;
return skinElement;
}
protected override TokenEditCheckedItemCollection CreateCheckedItemCollection() {
return new CustomTokenEditCheckedItemCollection(this);
}
protected override TokenEditSelectedItemCollection CreateSelectedItemCollection() {
return new CustomTokenEditSelectedItemCollection(this);
}
protected override TokenEditToken CreateTokenInstance(string description, object value, bool autoPopulated) {
CustomTokenEditToken token = new CustomTokenEditToken(description, value, this as RepositoryItemCustomTokenEdit);
return token;
}
public event EventHandler<TokenCheckedChangedEventArgs> TokenCheckedChanged;
protected internal void OnTokenCheckedChanged(CustomTokenEditToken token, bool repaint) {
RepaintEditIfRequired(repaint);
RaiseTokenCheckedChanged(token);
}
private void RaiseTokenCheckedChanged(CustomTokenEditToken token) {
EventHandler<TokenCheckedChangedEventArgs> handler = TokenCheckedChanged;
if (handler != null)
handler(this, new TokenCheckedChangedEventArgs(token));
}
private void RepaintEditIfRequired(bool repaint) {
CustomTokenEdit edit = OwnerEdit as CustomTokenEdit;
if (repaint && edit != null)
edit.Repaint();
}
}
}
C#using System;
using System.Collections.Generic;
using System.Linq;
namespace TokenEdit_Glyph_InEndOfToken.CustomTokenEdit
{
public class TokenCheckedChangedEventArgs : EventArgs
{
public TokenCheckedChangedEventArgs(CustomTokenEditToken _token)
{
Token = _token;
}
public CustomTokenEditToken Token { get; private set; }
}
}
C#using DevExpress.XtraEditors;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using TokenEdit_Glyph_InEndOfToken.CustomTokenEdit;
namespace TokenEdit_Glyph_InEndOfToken
{
public partial class Form1 : XtraForm
{
public Form1()
{
InitializeComponent();
InitToken();
InitGridControl();
}
private void InitToken()
{
tokenEdit1.Properties.ValidateToken += tokenEdit1_ValidateToken;
tokenEdit1.EditValue = "test@mail.com,test@test.com,test@microsoft.com";
tokenEdit1.Properties.TokenCheckedChanged += TokenCheckedChanged;
}
private void InitGridControl()
{
RepositoryItemCustomTokenEdit edit = new RepositoryItemCustomTokenEdit();
edit.Separators.AddRange(new string[] { "," });
edit.EditMode = TokenEditMode.Manual;
edit.ValidateToken += tokenEdit1_ValidateToken;
edit.TokenCheckedChanged += TokenCheckedChanged;
List<Test> lst = new List<Test>();
for (int i = 0; i < 10; i++)
lst.Add(new Test() { Token = string.Format("test{0}@mail.com", i) });
gridControl1.DataSource = lst;
gridControl1.RepositoryItems.Add(edit);
gridView1.Columns[0].ColumnEdit = edit;
}
readonly Regex MailRegex = new Regex(@"^[-a-z0-9!#$%&'*+/=?^_`{|}~]+(?:\.[-a-z0-9!#$%&'*+/=?^_`{|}~]+)*@(?:[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?\.)*(?:aero|arpa|asia|biz|cat|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|pro|tel|travel|[a-z][a-z])$", RegexOptions.Compiled);
private void tokenEdit1_ValidateToken(object sender, TokenEditValidateTokenEventArgs e)
{
e.IsValid = MailRegex.IsMatch(e.Description);
}
private void TokenCheckedChanged(object sender, TokenCheckedChangedEventArgs e)
{
XtraMessageBox.Show(string.Format("{0} {1} Checked: {2}", e.Token.Description, e.Token.Value, e.Token.Checked));
}
private void simpleButton2_Click(object sender, EventArgs e)
{
if (tokenEdit1.CheckedItem != null)
tokenEdit1.CheckedItem.Checked = !tokenEdit1.CheckedItem.Checked;
}
class Test
{
public object Token { get; set; }
}
}
}