基于XSD模式的WPF XmlDataProvider验证

3
我正在编写一款C#(3.5或4版本,如果我找到理由)WPF应用程序,使用XamlReader动态加载XAML片段以显示可自定义的UI。在显示之前,该UI绑定到XmlDataProvider,似乎工作得非常好。
我一直在尝试弄清楚是否可能让数据源(指向XML文档的XmlDataProvider)自动验证文档的XSD模式?
为了澄清一下,我试图避免编写任何自定义验证规则,因为应用程序具有可变性质。 XSD模式已经指定了限制(例如正则表达式或最大长度约束),我希望我的UI能以类似于Winforms错误提供程序的方式做出响应。
非常感谢你的帮助!
(顺便说一句-本想标记XmlDataProvider但基于声誉要求无法创建新标记)

这里有几个有趣的理由可以使用WPF 4.0而不是3.5...(如果我找到了理由的话)。 - Federico Berasategui
@HighCore 谢谢你提供的链接 :) 但我已经被 .NET 的较新版本的好处所吸引了!我试图坚持使用 v3.5 的原因是应用程序的用户通常没有在他们的工作站上安装 .NET 4 运行时,而且说服那些有权力的人相信新的运行时是一件困难的事情。办公室政治和开发人员不搭配... - Jay
WPF 3.5存在着一个非常严重的模糊文本问题。这可能会帮助您说服他们。 - Federico Berasategui
1个回答

3
我曾处理过类似的问题:动态加载XAML并验证用户输入。但是在我的情况下,我有一个全局的DataContext,所有加载的控件都与该上下文绑定。当执行验证操作时,例如用户点击“验证”数据按钮,DataContext会序列化为XML,然后我使用XSLT从此XML获取错误标记,但我认为如果您可以将DataContext序列化为XSD,则可以使用XSD。

我的步骤:

  1. Loading Xaml and setting my object to container DataContext

    String xaml="some xaml";
    MyData myData=new MyData();
    TextReader textReader = new StringReader(CardContext.Xaml);
    XmlReader xmlReader = XmlReader.Create(textReader);
    //setting DataContext for panel named 'content'
    this.content.DataContext = myData;
    FrameworkElement myContent = (FrameworkElement) XamlReader.Load(xmlReader);
    this.content.Children.Clear();
    this.content.Children.Add(myContent);
    InitMyComponents(this.content);
    
  2. Controls inside xaml bind to DataContext. DataContext is class MyData Like that:

    public class MyData
    {
        IDictionary<String, MyControl> MyControls{get;set;}
        ....
    }
    

    Where

    class MyControl
    {
       String Id{get;set;}
       String Name{get;set;}
       String Value{get;set;}
    }
    

    Getting binding for controls

    public static  Binding GetValueBinding(MyControl control)
    {
       Binding valueBinding = new Binding();
       valueBinding.Mode = BindingMode.TwoWay;
       valueBinding.Path = new PropertyPath("MyControls["+control.Id+"].Value");
       return valueBinding;
    }
    
  3. User working with controls and changing some values.

  4. When user need validation I put data in XSD schema named MyMetaData (inside that scheme I have table MyControls).

    MyMetaData _myMetaData;
    
    public void PushData(MyData myData)
        {
    
            foreach (MyControl control in myData.MyControls)
            {
             //fill table from xsd schema
       this._myMetaData.MyControls.AddMyControlsRow(control.Id,control.Name,control.Value);
    
    
            }
    
            this._myMetaData.AcceptChanges();
        }
    
  5. Getting XML from DataTable

    this._myMetaData.MyControls.GetXml()
    
  6. Validating XML using xslt

    XslCompiledTransform xslCompiledTransform = new XslCompiledTransform(); 
    String xml = "some xml";
    TextReader textReader = new StringReader(xml );
    XmlReader xmlReader = XmlReader.Create(textReader);
    StringBuilder validationResult = new StringBuilder();
    XmlWriter xmlWriter = XmlWriter.Create(validationResult);
    //aply xslt (xslt return tags with error description and control Id)
    xslCompiledTransform.Transform(xmlReader, xmlWriter);
    //parsing result tags
    IList<ValidationError> parsedResult = ParseValidationResult(validationResult.ToString());
    
  7. Finding controls and execute method for show error info

    DependencyObject errorSource = LogicalTreeHelper.FindLogicalNode(this.content, error.Identifier);
    if (errorSource == null)
        return;
    if (errorSource is MyControl)
       (errorSource as MyControl).ShowErrorInfo(error.ErrorText);
    
这是我的算法,但如果你对XSD架构有一些限制,当你将数据放到DataTable中的第4步时,就会出现错误。

所以这就是我正在做的事情...我有一个由XAML片段定义的控件(比如StackPanel),其中包含一个静态资源,即XMlDataProvider。当加载XAML片段的代码执行时,它通过设置数据源将XMLDataProvider绑定到XMLDocument。目前,我有一个单独的按钮,用于使用SchemaSet验证XMLDocument并在消息框中显示所有错误。您是说您可以将这些错误映射回特定的控件,以便验证机制可以在相关控件的上下文中显示错误吗? - Jay
添加我的算法描述 - Frank59
谢谢提供的信息 - 这看起来是一个正确方向的指针。我稍后会仔细研究它,并告诉你这是否是解决我的问题的答案。 - Jay

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接