2

缩小的解决方案
我更接近,但不知道如何应用 XAML 来更改 datacontext 值。请根据需要查看下面原始问题的上下文。

我的问题是我有一个 ViewModel 类作为窗口的数据上下文。在这个视图模型上,我有一个“DataTable”对象(带有列和只有一行用于测试)。当我尝试将文本框“TEXT”绑定设置到数据表的列时,它不起作用。我最终发现的是,无论我给它什么“来源”或“路径”,它都不会合作。然而,只是通过玩一些场景,我说得对。我们看看吧。文本框控件有自己的“DataContext”属性。因此,在代码中,我只是强制 textbox.DataContext = "MyViewModel.MyDataTableObject" 并将路径留给它应该代表 "MyDataColumn" 的列,并且它起作用了。

因此,也就是说,我将如何为文本框控件编写 XAML,以便将其“DataContext”属性设置为窗口视图模型的数据表对象的属性,但无法正确设置。前任:

<TextBox Name="myTextBox" 
    Width="120"
    DataContext="THIS IS WHAT I NEED" --- to represent
    Text="{Binding Path=DataName, 
                    ValidatesOnDataErrors=True,
                    UpdateSourceTrigger=PropertyChanged }" />

此文本框的 DataContext 应反映下面的 XAML 详细信息并获取

(ActualWindow) (DDT = 视图模型) (oPerson = 存在于视图模型上的数据表) CurrentWindow.DDT.oPerson




我被困在有约束力的东西上。我想将数据表的一列绑定到文本框控件。听起来很简单,但我错过了一些东西。先说简单的场景。如果我有我的窗口并将数据上下文设置为“MyDataTable”,并且有文本框 PATH=MyDataColumn,那么一切正常,没有问题,包括数据验证(红色边框错误)。

现在,问题。如果我直接在我的 Window 类上有一个与 public 相同的“MyDataTable”(但如果我在一个实际的 ViewModel 对象上有它,但窗口是为了简化级别引用),我无法让它工作直接 XAML 源。我知道我必须设置“SOURCE=MyDataTable”,但只是列的路径不起作用。

<TextBox Name="myTextBox" 
         Text="{Binding  Source=DDT, Path=Rows[0][DataName], 
                         ValidatesOnDataErrors=True,
                         UpdateSourceTrigger=PropertyChanged }" />

但是,从其他测试来看,如果我将路径(在代码隐藏中)设置为

object txt = FindName("myTextBox");
Binding oBind = new Binding("DataName");
oBind.Source = DDT;
oBind.Mode = BindingMode.TwoWay;
oBind.ValidatesOnDataErrors = true;
oBind.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
((TextBox)txt).SetBinding(TextBox.TextProperty, oBind);

它确实有效(当数据表在窗口(或视图模型)中作为公共可用时)

否则我错过了什么。

更新:这是我在此处应用的示例代码的完整帖子。

using System.ComponentModel;
using System.Data;

namespace WPFSample1
{
  /// <summary>
  /// Interaction logic for MainWindow.xaml
  /// </summary>
  public partial class MainWindow : Window
  {
    public DerivedDataTable DDT;

    public MainWindow()
    {
      InitializeComponent();
      // hook up to a Data Table 
      DDT = new DerivedDataTable();
      DataContext = this;

      // with THIS part enabled, the binding works.  
      // DISABLE this IF test, and binding does NOT.
      // but also note, I tried these same settings manually via XAML.
      object txt = FindName("myTextBox");
      if( txt is TextBox)
      {
        Binding oBind = new Binding("DataName");
        oBind.Source = DDT;
        oBind.Mode = BindingMode.TwoWay;
        oBind.ValidatesOnDataErrors = true;
        oBind.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
        ((TextBox)txt).SetBinding(TextBox.TextProperty, oBind);
      }
    }
  }

  // Generic class with hooks to enable error trapping at the data table
  // level via ColumnChanged event vs IDataErrorInfo of individual properties
  public class MyDataTable : DataTable
  {
    public MyDataTable()
    {
      // hook to column changing
      ColumnChanged += MyDataColumnChanged;
    }

    protected void MyDataColumnChanged(object sender, DataColumnChangeEventArgs e)
    { ValidationTest( e.Row, e.Column.ColumnName); }

    // For any derived datatable to just need to define the validation method
    protected virtual string ValidationTest(DataRow oDR, string ColumnName)
    { return ""; }
  }

  public class DerivedDataTable : MyDataTable
  {
    public DerivedDataTable()
    {
      // simple data table, one column, one row and defaulting the value to "X"
      // so when the window starts, I KNOW its properly bound when the form shows
      // "X" initial value when form starts
      Columns.Add( new DataColumn("DataName", typeof(System.String))  );
      Columns["DataName"].DefaultValue = "X";

      // Add a new row to the table
      Rows.Add(NewRow());
    }

    protected override string ValidationTest(DataRow oDR, string ColumnName)
    {
      string error = "";
      switch (ColumnName.ToLower())
      {
        case "dataname" :
          if (   string.IsNullOrEmpty(oDR[ColumnName].ToString() )
            || oDR[ColumnName].ToString().Length < 4 )
            error = "Name Minimum 4 characters";

          break;
      }

      // the datarow "SetColumnError" is what hooks the "HasErrors" validation
      // in similar fashion as IDataErrorInfo.
      oDR.SetColumnError(Columns[ColumnName], error);

      return error;
    }
  }
}

这是 XAML。任何全新的窗体,这是窗口默认“网格”中的唯一控件。

尝试了以下版本,只定义了 Rows[0][Column]

<TextBox Name="myTextBox" 
    Width="120"
    Text="{Binding  Path=Rows[0][DataName], 
                    ValidatesOnDataErrors=True,
                    UpdateSourceTrigger=PropertyChanged }" />

包括“滴滴涕”的来源,因为它对窗口是公开的

<TextBox Name="myTextBox" 
    Width="120"
    Text="{Binding  Source=DDT, Path=Rows[0][DataName], 
                    ValidatesOnDataErrors=True,
                    UpdateSourceTrigger=PropertyChanged }" />

甚至grantnz提供的建议

4

2 回答 2

0

我认为当您期望它成为当前窗口上的属性 DDT 时,您的 xaml 将源设置为字符串“DDT”。

您是否在 Visual Studio 的输出窗口中看到错误,例如:

System.Windows.Data Error: 40 : BindingExpression path error: 
'Rows' property not found on 'object' ''String' (HashCode=1130459074)'.
BindingExpression:Path=Rows[0][DataName]; DataItem='String' (HashCode=1130459074); 
target element is 'TextBox' (Name=''); target property is 'Text' (type 'String')

如果将窗口 DataContext 设置为此(来自代码 DataContext = this; 或xaml),则可以使用:

     Text="{Binding  Path=DDT.Rows[0][DataName], 
                     ValidatesOnDataErrors=True,
                     UpdateSourceTrigger=PropertyChanged }" />

或者您可以将 DataContext 保留为 null 并使用:

    <TextBox Name="myTextBox" 
     Text="{Binding  RelativeSource={RelativeSource FindAncestor, 
           AncestorType={x:Type Window}},Path=DDT.Rows[0][DataName], 
                     ValidatesOnDataErrors=True,
                     UpdateSourceTrigger=PropertyChanged }" />

以上假设您在设置绑定之前设置 DDT 属性。如果在配置绑定后设置了 DDT,则需要实现 INotifyPropertyChanged。

这是工作版本的来源(从 XAML 设置 DataContext 并实现了 INotifyPropertyChanged)。如果您注释掉该行,它将不起作用

OnPropertyChanged(new PropertyChangedEventArgs("DDT"));

如果您从 XAML 中省略以下内容,则第二个 TextBox 将被绑定

DataContext="{Binding RelativeSource={RelativeSource Self}}"

代码

public partial class MainWindow : Window, INotifyPropertyChanged
{

    public DataTable DDT { get; set; }
    public String SP { get; set; }

    public MainWindow()
    {

        InitializeComponent();
        DDT = new DerivedDataTable();
        OnPropertyChanged(new PropertyChangedEventArgs("DDT"));
        SP = "String prop";
    }
    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, e);
    }        

}

XAML

<Window x:Class="BindingTest.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525"
    DataContext="{Binding RelativeSource={RelativeSource Self}}">

<StackPanel>
    <TextBox 
     Text="{Binding  RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}},Path=DDT.Rows[0][DataName], 
                     ValidatesOnDataErrors=True,
                     UpdateSourceTrigger=PropertyChanged }" />
    <TextBox
     Text="{Binding  Path=DDT.Rows[0][DataName], 
                     ValidatesOnDataErrors=True,
                     UpdateSourceTrigger=PropertyChanged }" />
    <TextBox
     Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}},Path=SP}" />
    </StackPanel>
</Window>
于 2012-04-29T06:00:01.757 回答
0

已解决,但是 PITA 是什么... MVVM 模式示例中的大多数内容都会在视图模型上具有属性,从而暴露您想要挂钩的任何内容。在处理绑定到 DATATABLE(或类似视图等)时,您将绑定到所述表(或视图)的 COLUMN。

当从任何后端查询表时,填充数据列的模式将始终强制列名为大写。

因此,如果您的表中有一个列“InvoiceTotal”,则在查询时,列名将其为“INVOICETOTAL”。

如果您尝试绑定到

Path="InvoiceTotal" ... it will fail

Path="INVOICETOTAL" ... it WILL WORK

但是,如果您直接在 .Net 中工作(我使用 C#),则以下内容都将从行中返回一个值

double SomeValue = (double)MyTable.Rows[0]["InvoiceTotal"];
or
double SomeValue = (double)MyTable.Rows[0]["INVOICETotal"];
or
double SomeValue = (double)MyTable.Rows[0]["invoicetotal"];

无论列名是否区分大小写。

因此,现在其余的绑定,在表、行或列级别可用的错误触发器可以正确地反映在 GUI 中给用户。

我当然希望这可以为其他人省去我对此进行的头痛和研究....

于 2012-05-01T19:13:01.957 回答