Cascading Drop-Down List trong InfoPath Browser form

Chúng ta biết rằng việc sử lý giao diện theo kiểu master/detail hay cascading là rất hay gặp. Lấy ví dụ cho một cascading phổ biến là Address (địa chỉ). Tôi có 3 drop-down list bao gồm: Tỉnh thành phố (province), quân huyên (district) và phường xã (ward). Khi tôi select tỉnh thành phố, thì drop-down list quận huyện sẽ tự động fill theo tỉnh thành phố đó. Tương tự khi tôi select quận huyện, thì drop-down list phường xã cũng fill theo quận huyện đó.

image

Bài toán này, nếu sử dụng InfoPath không hỗ trợ browser form thì sẽ rất là đơn giản. Chúng tả chỉ cần sử dụng tính năng Filter của InfoPath control là đủ. Tuy nhiên, đối với InfoPath Browser support, các bạn biết rằng không sử được tính năng filter trên, dó đó buộc chúng ta phải can thiệp vào InfoPath Object Model. Trên web cũng có một số bài viết về việc xử lý Cascading Drop-Down List trong InfoPath sử dụng Web Service. Tuy nhiên, điều này hơi bất cấp trong việc deploy webservice và lưu trữ giữ liệu trên SQL để cho Web Service query.

Hôm nay tôi giới thiệu cho các bạn một cách xử lý Cascading  Drop-Down List nhiều cấp cho InfoPath browser form support bằng cách sử dụng InfoPath Object Model và XPath query.

Trước hết chúng ta thiết kế một XML file để lưu trữ dữ liệu cho các drop-down như sau:

<?xml version="1.0" encoding="utf-8" ?>
<DiaChi>
  <TinhTP>
    <tenTinhTP>Hanoi</tenTinhTP>
    <QuanHuyen>
      <tenQuanHuyen>Cau Giay</tenQuanHuyen>
      <PhuongXa>
        <tenPhuongXa>Dich Vong</tenPhuongXa>
      </PhuongXa>
      <PhuongXa>
        <tenPhuongXa>Mai Dich</tenPhuongXa>
      </PhuongXa>
    </QuanHuyen>
    <QuanHuyen>
      <tenQuanHuyen>Dong Da</tenQuanHuyen>
      <PhuongXa>
        <tenPhuongXa>Dong Tam</tenPhuongXa>
      </PhuongXa>
    </QuanHuyen>
  </TinhTP>
  <TinhTP>
    <tenTinhTP>Hai Phong</tenTinhTP>
    <QuanHuyen>
      <tenQuanHuyen>Le Chan</tenQuanHuyen>
      <PhuongXa>
        <tenPhuongXa>Cu Lai</tenPhuongXa>
      </PhuongXa>
    </QuanHuyen>
    <QuanHuyen>
      <tenQuanHuyen>Gia Dinh</tenQuanHuyen>
      <PhuongXa>
        <tenPhuongXa>Cam Thuong</tenPhuongXa>
      </PhuongXa>
      <PhuongXa>
        <tenPhuongXa>Dong Quang</tenPhuongXa>
      </PhuongXa>
    </QuanHuyen>
  </TinhTP>
</DiaChi>

Sau đó chúng ta add file xml này vào Data Connections của InfoPath

Tiếp theo chúng ta xử lý các Event:ChangedEventHandler đối với 3 drop-down list

Trước hết chúng ta đăng ký các Event

public void InternalStartup()
       {
           EventManager.FormEvents.Loading += new LoadingEventHandler(FormEvents_Loading);
           EventManager.XmlEvents["/my:myFields/my:tinhTP"].Changed += new XmlChangedEventHandler(tinhTP_Changed);
           EventManager.XmlEvents["/my:myFields/my:quanHuyen"].Changed += new XmlChangedEventHandler(quanHuyen_Changed);
       }

Trong khi load form chúng ta binding và Tỉnh thành phố drop-Down

public void FormEvents_Loading(object sender, LoadingEventArgs e)
        {           
            AddTinhTPs();
        }

        private void AddTinhTPs()
        {          
            try
            {

                XPathNavigator navAddress = DataSources["Address"].CreateNavigator();

                // Compile a standard XPath expression
                XPathExpression exprTinhTP;
                exprTinhTP = navAddress.Compile("/DiaChi/TinhTP/tenTinhTP");
                XPathNodeIterator iteratorTinhTP = navAddress.Select(exprTinhTP);
                if (iteratorTinhTP != null && iteratorTinhTP.Count >= 1)
                {
                    XPathNavigator nav = this.CreateNavigator().SelectSingleNode("/my:myFields/my:TinhTPs", this.NamespaceManager);
                    while (iteratorTinhTP.MoveNext())
                    {
                        XPathNavigator newNode = null;
                        newNode = nav.Clone();
                        newNode.SelectSingleNode("/my:myFields/my:TinhTPs/my:tinhTPDisplayName", this.NamespaceManager).SetValue(iteratorTinhTP.Current.Value);
                        newNode.SelectSingleNode("/my:myFields/my:TinhTPs/my:tinhTPValue", this.NamespaceManager).SetValue(iteratorTinhTP.Current.Value);
                        nav.InsertAfter(newNode);
                        newNode = null;
                    }
                    nav.DeleteSelf();
                    nav = null;
                }
            }
            catch (Exception ex)
            {
                WriteLog(ex.ToString());
            }
        }

Xử lý Event khi select item trong Tỉnh thành phố. Lúc này chúng ta mới binding đối với Quận huyện Drop-Down list

public void tinhTP_Changed(object sender, XmlEventArgs e)
        {           
            string selectedTinhTP = this.CreateNavigator().SelectSingleNode("/my:myFields/my:tinhTP", this.NamespaceManager).Value;
            if (!string.IsNullOrEmpty(selectedTinhTP))
            {
                WriteLog("tinhTP_Changed:" + selectedTinhTP + "/" + e.NewValue);
                AddQuanHuyens(selectedTinhTP);
            }
        }

private void AddQuanHuyens(string selectedTinhTP)
        {
           try
           {
               XPathNavigator navAddress = DataSources["Address"].CreateNavigator();
               // Compile a standard XPath expression
                XPathExpression exprQuanHuyen;
                string exprXPath = "/DiaChi/TinhTP[tenTinhTP=’" + selectedTinhTP + "’]/QuanHuyen/tenQuanHuyen";
                exprQuanHuyen = navAddress.Compile(exprXPath);
                XPathNodeIterator iteratorQuanHuyen = navAddress.Select(exprQuanHuyen);

                if (iteratorQuanHuyen != null && iteratorQuanHuyen.Count >= 1)
                {
                    ClearGroupNode("QuanHuyens");
                    XPathNavigator nav = this.CreateNavigator().SelectSingleNode("/my:myFields/my:QuanHuyens", this.NamespaceManager);
                    while (iteratorQuanHuyen.MoveNext())
                    {
                        XPathNavigator newNode = null;
                        newNode = nav.Clone();
                        newNode.SelectSingleNode("/my:myFields/my:QuanHuyens/my:quanHuyenDisplayName", this.NamespaceManager).SetValue(iteratorQuanHuyen.Current.Value);
                        newNode.SelectSingleNode("/my:myFields/my:QuanHuyens/my:quanHuyenValue", this.NamespaceManager).SetValue(iteratorQuanHuyen.Current.Value);
                        nav.InsertAfter(newNode);
                        newNode = null;
                    }

                    nav.DeleteSelf();
                    nav = null;
                }
                WriteLog("AddQuanHuyens:" + exprXPath);
            }
            catch (Exception ex)
            {
                WriteLog(ex.ToString());
            }
        }

Tương tự, chúng ta xử lý cho Phường xã.

Toàn bộ source code cho Cascading Address này được đính kèm trong bài viết này, các bạn tham khảo và cho ý kiến.

Leave a Reply