2012-04-29 17 views
1

縮小解決方案
我非常接近,但不知道如何申請XAML來改變datacontext的價值。如有需要,請回顧下面的原始問題。WPF綁定的DataTable行列到文本框

我的問題是,我有一個ViewModel類作爲datacontext到一個窗口。在這個視圖模型上,我有一個「DataTable」對象(帶有列,只有一行用於測試)。當我嘗試將文本框「TEXT」綁定到數據表的列時,它不起作用。我最終發現的是,無論我給它什麼「源」或「路徑」,它都不會合作。但是,只是通過玩弄場景,我說了它。我們看看吧。 Textbox控件具有自己的「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,則一切正常,沒有問題,包括數據驗證(錯誤的紅色邊框)。

現在,問題所在。如果我在我的窗口類中直接使用與公共相同的「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。任何全新的窗體,這是窗口默認「網格」中的唯一控件。

嘗試以下版本,只是定義行[0] [專欄]

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

包括 「DDT」 的來源,因爲它是公衆對窗口

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

甚至建議提供通過grantnz

回答

0

求解,b ut什麼是PITA ......做MVVM模式的示例中的大部分內容都將在視圖模型上具有屬性,從而暴露您想要鉤入的任何內容。在處理綁定到DATATABLE(或類似的視圖等)時,您綁定到所述表(或視圖)的COLUMN。

從任何後端查詢表時,填充數據列的模式將始終強制列名爲UPPER CASE。

因此,如果您的表中有一列「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中給用戶。

我當然希望這樣可以節省別人的頭痛和研究,我曾經走過這個....

0

我想你的xaml是設置源的字符串「DDT」,當你期待它是當前窗口的屬性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 =本;或xaml),你可以使用:

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

,或者你可以離開的DataContext爲空及用途:

<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和INotifyPropertyChanged實現的DataContext集)。如果您註釋掉線

OnPropertyChanged(new PropertyChangedEventArgs("DDT")); 

和第二個文本框,如果你離開了以下出來的XAML

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

CODE

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> 
+0

Grantnz,不,我不是在暴食得到任何錯誤。我試過你的路徑= DDT.Rows [0] [DataName],這是不成功的。我試圖包括RelativeSource/FindAncestor也沒有工作。感謝您的建議,但。 – DRapp 2012-04-29 12:05:25

+0

@DRapp - 您是否在配置綁定之前或之後設置了DDT?如果您是從窗口構造函數中的代碼設置它,請嘗試將代碼移到InitializeComponent()上面。 (或實現INotifyPropertyChanged)。 – grantnz 2012-04-29 20:27:24

+0

@DRapp - 我很驚訝你在輸出窗口中看不到任何綁定錯誤。如果你故意發生錯誤會發生什麼(例如Path = PropertyThatDoesntExist)? – grantnz 2012-04-29 20:39:52