【问题标题】:Drag XmlElement from one Listbox to another empty Xml bound listbox将 XmlElement 从一个列表框拖到另一个空的 Xml 绑定列表框
【发布时间】:2017-02-17 15:59:05
【问题描述】:

我有两个列表框,它们都绑定到两个不同的 XML 文件。 目的是将 XmlElements 从一个文件拖到另一个文件(ListBox)中。

当我从一个已填充的 ListBox 拖动到另一个已填充的 ListBox 时,目标 ListBox 中的代码相当简单。 但是当目标 ListBox 为空时,由于 ListBox 不包含任何项,因此很难获取任何 XmlElements。

由于未填充目标,因此代码将在以下位置失败:

XmlElement targetXmlElement = (XmlElement)parent.Items.GetItemAt(0);

所以问题是: 如何从 ListBox-target 中获取 XmlDataProvider 或 XmlDocument:ListBox parent = (ListBox)sender;

另一个问题是目标列表框应该包含一个子节点列表,即我们拖动元素的目标。 如何访问父元素?

ListBox dragSource = null;
    private void FoodListBox_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        ListBox parent = (ListBox)sender;
        dragSource = parent;
        object data = GetDataFromListBox(dragSource, e.GetPosition(parent));

        if (data != null)
        {
            DragDrop.DoDragDrop(parent, data, DragDropEffects.Copy);
        }
    }

    #region GetDataFromListBox(Listbox, Point)
        private static object GetDataFromListBox(ListBox source, Point point)
        {
            UIElement element = source.InputHitTest(point) as UIElement;
            if(element != null)
            {
                object data = DependencyProperty.UnsetValue;
                while(data == DependencyProperty.UnsetValue)
                {
                    data = source.ItemContainerGenerator.ItemFromContainer(element);
                    if (data == DependencyProperty.UnsetValue)
                    {
                        element = VisualTreeHelper.GetParent(element) as UIElement;   
                    }
                    if (element == source)
                    {
                        return null;
                    }
                }       
                if(data != DependencyProperty.UnsetValue)
                {
                    return data;
                }         
            }

            return null;
        }
    #endregion


    //This listbox is bound to Dataprovider2, Objects dragged into will access the XML target 
    private void ListBox_Drop(object sender, DragEventArgs e)
    {
        ListBox parent = (ListBox)sender;

        //Get access to the element from the source XML
        XmlElement sourceXmlElement = (XmlElement)e.Data.GetData(typeof(XmlElement));

        //Get the position of the parent to any Element in the the target list (e.g the zero element)
        XmlElement targetXmlElement = (XmlElement)parent.Items.GetItemAt(0);

        AppendXmlNode(sourceXmlElement, targetXmlElement);
    }

【问题讨论】:

  • listbox-target 使用 Xpath="/recipelist/recipe[contains(.,'name')]/foodlist/foodtype" 过滤,这意味着 foodlist 为空,xpath 不返回任何内容跨度>

标签: c# xml wpf listbox xmldocument


【解决方案1】:

在 WPF 中,您不是直接绑定到集合,而是绑定到该集合的 default view

所有集合都有一个默认的 CollectionView。 WPF 总是绑定到一个 视图而不是集合。如果你直接绑定到一个集合, WPF 实际上绑定到该集合的默认视图。这 默认视图由​​集合的所有绑定共享,这会导致 所有直接绑定到集合以共享排序、过滤器、 组,以及一个默认视图的当前项目特征。

您可以从绑定源中提取XmlDocument,而不是获取过滤后的视图。

private void targetListBox_Drop(object sender, DragEventArgs e)
{
    ListBox parent = (ListBox)sender;

    //Get access to the element from the source XML
    XmlElement sourceXmlElement = (XmlElement)e.Data.GetData(typeof(XmlElement));

    //Get access to the document from the target XML
    BindingExpression bindingExpression = 
        parent.GetBindingExpression(ListBox.ItemsSourceProperty);
    Binding parentBinding = bindingExpression.ParentBinding;
    XmlDataProvider source = (XmlDataProvider)parentBinding.Source;
    XmlDocument targetXmldocument = source.Document;

    AppendXmlNode(sourceXmlElement, targetXmldocument);
}

一旦你掌握了文档,修改就轻而易举了。

private static void AppendXmlNode(XmlElement element, XmlDocument doc)
{
    //Get access to the root node to append child
    XmlNode root = doc.SelectSingleNode("/recipelist/recipe[contains(.,'name')]/foodlist");
    //Detach element from source XmlDocument
    XmlNode clone = doc.ImportNode(element, true);
    root.AppendChild(clone);
}

【讨论】:

    【解决方案2】:

    感谢 bab7lon 的精彩回答!

    虽然代码 sn-p 确实将 source 返回为 null:

    BindingExpression bindingExpression = parent.GetBindingExpression(ListBox.ItemsSourceProperty);
    Binding parentBinding = bindingExpression.ParentBinding;
    XmlDataProvider source = (XmlDataProvider)parentBinding.Source;
    

    但过了一会儿我意识到object sender 实际上包含一个DataContext。

    以下代码解决了我的问题:

        private void ListBox_Drop(object sender, DragEventArgs e)
        {
            ListBox parent = (ListBox)sender;
    
            //Get access to the element from the source XML
            XmlElement sourceXmlElement = (XmlElement)e.Data.GetData(typeof(XmlElement));
    
            XmlDataProvider l_context = (XmlDataProvider)parent.DataContext;
            XmlDocument l_XmlDoc = l_context.Document;
            string l_Xpath = l_context.XPath;
            XmlNode l_node = l_XmlDoc.SelectSingleNode(l_Xpath.Replace("/foodlist/foodtype",""));
            XmlElement targetXmlElement = (XmlElement)l_node.SelectSingleNode("foodlist");
    
            AppendXmlNode(sourceXmlElement, targetXmlElement);
        }
    
        private void AppendXmlNode(XmlElement source, XmlElement target)
        {
            XmlElement l_source = source;
            XmlElement l_target = target;
    
            //Append first the Parent 
            XmlNode l_nodeToCopy = l_target.OwnerDocument.ImportNode(l_source, true);
            l_target.AppendChild(l_nodeToCopy);
    
            XmlDocument l_doc = l_target.OwnerDocument;
            Save(l_doc);
        }
    

    【讨论】:

    • 我的 sn-p 使用 XmlDataProvider 作为资源(参考 docs)。再说一次,给猫剥皮的方法不止一种。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-28
    • 2023-03-27
    相关资源
    最近更新 更多