一个基于文本的列表+查找控件

 

介绍 曾经想要创建一 个外观风格的文本框,它解析内容 输入并根据某个数据源进行验证?这是我的实现 这样的控制。 步骤A -需要内部对象 我尽量保持对象模型的全局,以便它能满足大多数需求。 作为基础,我使用RichTextBox控件,从该控件继承编辑和格式化 文本的显示。 控件的特性:我允许标准的分隔字符';' 和',' -但由于它是一个数组,您可以添加或更改它们需要。 现在,由于我不想编写文本编辑器,而是将重点放在查找功能上, 我创建了一个类(RichTextList),它继承了 System.Windows.Forms。并包装了一些用于选择的逻辑 点击进去。这样,我也有了一个本机方式来打印 列表的格式(颜色、粗体、下划线等)。 当然,RTF控件并不是轻量级的,所以我们可以考虑 放下它,内联渲染,但另一方面,它被包括在内 在。net框架中,所以它并不是二进制的。 隐藏,复制Code

//
// This class is only used internally -
// out control will not expose any of it directly
//
class RichTextList : System.Windows.Forms.RichTextBox {
  ...
  public char[] SeparationChars = new char[] {';',','};
  // which chars are interpreted as object-separators
  ...

我们覆盖了一些继承的事件,这样我们就可以捕获正在尝试的用户 点击或选择某物。当用户单击时,我们尝试选择 用户单击进入的项。我们不希望用户能够更改写入操作 的已验证项。 隐藏,复制Code

protected override void OnSelectionChanged(EventArgs e) {
  if (this.NoSelChangeEvent) return;
  //at end of list
  if (base.SelectionStart == base.Text.Length) return;
  //selected whole list
  if (base.SelectionLength == base.Text.Length) return;
  if (base.SelectionLength == 0 //at sep-char
    && base.Text.IndexOfAny(this.SeparationChars,
    base.SelectionStart,1) > -1) return;
  this.MarkItem(base.SelectionStart); //within an item >> select it!
  base.OnSelectionChanged(e);
  if (base.SelectedText.Length > 0 && this.ItemSelected != null)
    this.ItemSelected(base.SelectedText);
}

这是我们的选择逻辑,它决定了开始和结束的位置 的当前点击/选择项目。也许,我是个老派的人,应该这么做 使用了RegExp -不确定哪种方式的性能更好。 隐藏,复制Code

// this function actually marks the item in the textbox
private void MarkItem(int Pos) {
  this.NoSelChangeEvent = true;
  /* Find first pos */
  if (Pos == base.Text.Length) Pos--;
  int x1 = base.Text.LastIndexOfAny(this.SeparationChars, Pos, Pos)+1;
  base.SelectionStart = x1;

  /* Find last pos */
  int x2 = base.Text.IndexOfAny(this.SeparationChars, Pos+1);
  base.SelectionLength = (x2<0?base.Text.Length:x2)-base.SelectionStart;
  this.NoSelChangeEvent = false;
}

现在,我们创建一个低权重对象,它将表示列表中的一个项。 的每个解析项将使用/实例化此对象 用户输入。基本上,它允许开发人员定义颜色 如果已经验证,它会显示在。当然,要想在全球范围内使用, 控件本身不能验证任何输入。 它通过ValidateItems事件通知容器, 只有在列表中有任何未验证的项时才会引发。 我们验证的点是引发的OnValidate事件 自动模糊或当父/表单请求验证。 隐藏,复制Code

//
// a low-weight Class to hold all parsed elements
//
public class ObjectItem {
  ...
  public System.Drawing.Color TextColor = System.Drawing.Color.Blue;
  // the default color of a validated item

当引发ValidateItems事件时,开发人员就会进行检查 确定未验证项的集合(见下文)。 为了验证它们,他只需处理输入的文本并进行验证 它根据一些后端逻辑,后者通常返回一些对象 或该对象的唯一标识符(如数据库ID、用户对象、 DataRow, GUID等等)。无论返回什么,它都可以被钩住 通过将其分配给ObjectRef,将其分配给ObjectItem。 如果ObjectRef不为null,则项目将按存在进行 验证-非常基础,非常简单,非常有效:)。 隐藏,复制Code

// wether this item has been validated or not
public bool Validated {
  get { return (this.ObjectRef != null); }
}

// a reference to the validated source.
// can be an ID value, an object-reference or any
// other means of locating the resource. If this object is null,
// then Validated returns false, else it returns true.
public object ObjectRef;

但是由于列表中可能有多个条目,所以需要一个集合 把它们都藏起来。我们将这个对象称为ObjectItemCollection -因为它是对象的集合。 让我把重点放在这些重要的实现上: 每当从列表中删除一个项目时,我们都希望了解它! 通常,开发人员希望从后端资源中删除该项 (例如数据库或业务对象),因此当 发生这种情况。现在,正如目前和以前解释的所有对象都不一样 包括我们正在构建的主要控件,您将看到它们之间的关系 在所有这些更深的下面。 隐藏,复制Code

//
// The collection which holds all entered elements
//
public class ObjectItemCollection : CollectionBase {

  ...
  // we have the UI control raise an event, if an item
  // has been removed from the collection
  protected override void OnRemoveComplete(int index, object value) {
    base.OnRemoveComplete (index, value);
    this.Textbox.OnRemoveItem((ObjectItem)value);
  }

当然,开发人员可以在任何时候添加项目到我们的控件- 这些通常已经经过验证,所以他可以提供ObjectRef 在这里。通过编程方式添加未经验证的内容是没有意义的 物品——在大多数情况下。即使是这样,也只需为objRef提供NULL。 隐藏,复制Code

// implementing code can add items to the Text/Listbox using this
// add method
public ObjectItem Add(string itemName, object objRef) {
  ObjectItem it = new ObjectItem(itemName, objRef);
  it.isNew = true;
  List.Add(it);
  return it;
}

步骤B -最后,“TextObjectList”用户控件本身 接下来,我们构建控件本身,它将引发事件并进行管理 列表的解析和构建。这个类我称为TextObjectList 它将是控件的类(因此,它是公共的), 因此它必须继承System.Windows.Forms.UserControl。 这里声明的事件是您将绑定到的事件。 上面的子对象只会将它们的操作报告给这个控件——由它来决定 如何进行和做决定。 隐藏,复制Code

// our event delegates
public delegate void ObjectItemRemovedEvent(TextObjectList list,
                                                   ObjectItem item);
public delegate void ObjectItemClickedEvent(TextObjectList list,
                                ObjectItem item, MouseEventArgs ev);
public delegate void ValidateObjectItemsEvent(ObjectItemCollection col);

public event ObjectItemClickedEvent ObjectItemClicked;
public event ObjectItemRemovedEvent ObjectItemRemoved;
public event ValidateObjectItemsEvent ValidateItems;

// this collection holds all entered items - validated and not
public ObjectItemCollection ObjectItems;

我们覆盖了验证事件,以便我们可以对用户输入进行操作 (实际上,在失去焦点或通过表单手动验证请求时采取行动)。 隐藏,收缩,复制Code

// we create our own validation code
public override bool Validate() {
  base.Validate();
  bool AllValid = true;
  string txtEntered = this.NList.Text;
  string intSep = "";
  foreach (char sepChar in this.intSepChar) {
    intSep += sepChar.ToString();
  }

  /* Replace all allowed Sep-Chars with our internal one
   * so we can split the input */
  foreach (char sepChar in this.SeparationChars) {
    txtEntered = txtEntered.Replace(sepChar.ToString(), intSep);
  }

  /* Now split the input */
  string[] txtItems = txtEntered.Split(this.intSepChar);

  /* Then parse each item */
  ArrayList idxs = new ArrayList();
  foreach (string txtItem in txtItems) {
    if (txtItem.Trim() == string.Empty) continue;
    Debug.WriteLine(" .. parsing txtItem " + txtItem.Trim(),
                                       "TextObjectList.Validate");
    if (this.ObjectItems.Contains(txtItem.Trim())) {
      idxs.Add( this.ObjectItems.IndexOf(
        this.ObjectItems.FindByName(txtItem.Trim())
        ));
      continue;
    }
    //not in collection yet, add it!
    ObjectItem it = new ObjectItem(txtItem.Trim());
    this.ObjectItems.Add(it);
    idxs.Add( this.ObjectItems.IndexOf(it) );
  }

  /* Now remove all items not in array */
  for (int i = this.ObjectItems.Count-1; i >= 0; i--) {
    if (idxs.Contains(i)) continue;
    if (this.ObjectItems.Item(i).isNew) continue;
    this.ObjectItems.RemoveAt(i);
  }

  /* Something to validate by host? */
  AllValid = true;
  foreach (ObjectItem it in this.ObjectItems) {
    if (!it.Validated) AllValid = false;
  }

  /* Now have the host validate all new items */
  if (!AllValid && this.ValidateItems != null)
    this.ValidateItems(this.ObjectItems);

  /* Finally visually display all items */
  AllValid = true;
  string newRtf = "";
  string colTbl = BuildColorTable();
  foreach (ObjectItem it in this.ObjectItems) {
    it.isNew = false;
    if (it.Validated) {
      newRtf += @"\cf" + this.colors[it.TextColor.ToArgb()]
      + @"\ul\b " + it.ItemName + @"\b0\ulnone\cf0";
    } else {
      newRtf += @"\cf1 " + it.ItemName + @"\cf0";
      AllValid = false;
    }
    newRtf += " " + this.SeparationChars[0].ToString();
  }
  this.NList.Rtf = @"{
tf1\ansi\ansicpg1252\deff0\deflang3079"
+ @"{\fonttbl{\f0\fswiss\fcharset0 Arial;}}" + @"{\colortbl ;
ed255\green0\blue0;"
+ colTbl + "}" + @"{\*\generator TextObjectList.NET;}\viewkind4\uc1\pard\f0\fs20 " + newRtf + @"\par}"; return AllValid; }

下面是由下面的对象引发的事件——我们捕获和处理 他们适当的。 隐藏,复制Code

// ah, an item in the textbox has been clicked,
 // we check which one it is in our
// collection and raise the appropriate event
protected void NList_ItemClicked(string ItemName, MouseEventArgs e) {
  if (this.ObjectItemClicked == null) return;
  if (!this.ObjectItems.Contains(ItemName)) return;
  this.ObjectItemClicked(this, this.ObjectItems.FindByName(ItemName), e);
}

// our UI textbox wants to validate -
// so we check all items and don't let the textbox
// loose focus if an item in it could not be validated
protected void NList_Validating(object sender,
        System.ComponentModel.CancelEventArgs e) {
  e.Cancel = (!this.Validate());
}


// fire the event, if an item has been removed from the collection
internal void OnRemoveItem(ObjectItem value) {
  if (this.ObjectItemRemoved != null)
    this.ObjectItemRemoved(this, value);
}

的兴趣点 这个示例实际上向您简要介绍了以下主题 和技术:继承,委托和事件,控制构建,构建 collections。因为我使用ObjectItem对象来处理对象, 您既可以增强它,也可以从它继承您自己的扩展对象 它添加更多的功能,或形成它,以满足您的需要。 我希望这个代码是有用的。我在这里只展示了一些片段, 请使用以上连结下载源代码。 如果您有任何问题,请随时与我联系。 本文转载于:http://www.diyabc.com/frontweb/news362.html

posted @ 2020-08-06 01:19  Dincat  阅读(174)  评论(0编辑  收藏  举报