2012-04-29 2 views
1

сужен РЕШЕНИЕ
Я гораздо ближе, но не знает, как применить XAML для изменения DataContext значения. Пожалуйста, ознакомьтесь с контекстом первоначального вопроса ниже, если это потребуется.WPF Binding DataTable строка столбец в текстовое поле

Моя проблема заключается в том, что у меня есть класс ViewModel как datacontext для окна. В этой модели представления у меня есть объект «DataTable» (с столбцами и только одна строка для тестирования). Когда я пытаюсь привязать текстовое поле «ТЕКСТ» к столбцу данных, оно не работает. То, что я в конечном итоге нашел, - это то, что независимо от того, какой «источник» или «путь» я ему даю, он просто не будет сотрудничать. ОДНАКО, просто играя со сценариями, я сказал, черт возьми. Давайте посмотрим. Элемент управления Textbox имеет собственное свойство DataContext. Таким образом, в коде я просто FORCED 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 = View Model) (oPerson = DataTable, которая существует на модели представления) CurrentWindow.DDT.oPerson




Я застрял на что-то с обязательным. Я хочу привязать столбец данных к элементу управления текстовым полем. Звучит просто, но я чего-то не хватает. Сначала простейший сценарий. Если у меня есть мое окно и задано контекст данных для «MyDataTable», и у меня есть текстовое поле PATH = MyDataColumn, все работает нормально, никаких проблем, включая проверку данных (красная граница ошибок).

Теперь проблема. Если у меня есть тот же самый «MyDataTable» как публичный в моем Window Class напрямую (но то же самое, если бы я имел его на фактическом объекте 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); 

он работает (когда DataTable доступен как общественности в окне (или вид модели))

Что мне не хватает в противном случае.

ОБНОВЛЕНИЕ: ЗДЕСЬ ПОЛНАЯ ПОЧТА кода образца, который я подаю здесь.

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 }" /> 

В том числе источник «ДДТ», поскольку она является общедоступной к окну

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

И даже предложения, предлагаемые by grantnz

ответ

0

SOLVED, b ut, что PITA ... Большинство вещей в образцах шаблонов MVVM будут иметь свойства в модели представления, разоблачающие все, что вы хотите подключить. При работе с привязкой к DATATABLE (или аналогичному представлению и т. Д.) Вы привязываетесь к COLUMNs указанной таблицы (или представления).

Когда таблица запрашивается из любого исходного кода, схема, заполняющая столбцы данных, всегда будет приводить имена столбцов к 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"]; 

все независимо от чувствительности к регистру имени столбца.

Итак, теперь остальные привязки, триггеры ошибок, доступные на уровне таблицы, строки или столбца, могут быть правильно отражены в графическом интерфейсе для пользователя.

Я очень надеюсь, что это спасает кого-то головные боли и исследование, которое я пережил на этом ....

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 }" /> 

T он предполагает, что вы устанавливаете свойство DDT до привязки. Если после установки привязки установлен DDT, вам необходимо реализовать INotifyPropertyChanged.

Вот источник рабочей версии (с использованием DataContext из XAML и INotifyPropertyChanged). Это не работает, если вы закомментировать строку

OnPropertyChanged(new PropertyChangedEventArgs("DDT")); 

и второй TextBox обязан, если вы выходите из следующих из из XAML

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

Grantnz, нет, я не получаю сообщение об ошибке на кайфа. Я попробовал ваш Path = DDT.Rows [0] [DataName], и ​​это было неудачно. Я попытался включить RelativeSource/FindAncestor тоже, не работал. Спасибо за предложения. – DRapp

+0

@DRapp - Вы устанавливаете DDT до или после настройки привязки? Если вы устанавливаете его из кода в конструкторе окна, попробуйте переместить код выше InitializeComponent(); (или реализовать INotifyPropertyChanged). – grantnz

+0

@DRapp - Я удивлен, что вы не видите никаких ошибок привязки в окне вывода. Что произойдет, если вы сделаете преднамеренную ошибку (например, Path = PropertyThatDoesntExist)? – grantnz

Смежные вопросы