zoukankan      html  css  js  c++  java
  • 一个基于文本的列表+查找控件

    介绍 曾经想要创建一 个外观风格的文本框,它解析内容 输入并根据某个数据源进行验证?这是我的实现 这样的控制。 步骤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

  • 相关阅读:
    Queue——C#浅谈
    C#设计模式(7)——适配器模式
    test
    python 技巧
    在centos 配置python django环境 总结
    pyqt5 做的小程序,可以用来UI做个小demo
    python sqlalthemy 总结
    数据清理,预处理 pandas dataframe 操作技巧 总结
    对区块链看法
    hadoop spark 总结
  • 原文地址:https://www.cnblogs.com/Dincat/p/13443823.html
Copyright © 2011-2022 走看看