Pergunta

All, I have some test code that works with some test data defined as

private ObservableCollection<TestClass> _testData = new ObservableCollection<TestClass>();
public ObservableCollection<TestClass> TestData
{
    get { return _testData; }
    set { _testData = value; }
}

and is bound at design-time via

<DataGrid x:Name="dataGrid" ItemsSource="{Binding TestData}".../>

I have created a DataGrid which gets populated at run-time via

dataGrid.ItemsSource = BuildDataGridColumns(cultureDict).Tables[0].AsDataView();

with

private DataSet BuildDataGridColumns(Dictionary<string, string> cultureDict,
                                     DataTable additionalDt = null)
{
    // ...
}

Which works great, however the code that updates the grids visuals that used to work with the test data no longer does due to (I believe) ItemsSource="{Binding TestData}" being absent. The XAML that is supposed to bind the text inserted into a TextBox and that in the cells of the DataGrid is:

<DataGrid x:Name="dataGrid" 
          local:DataGridTextSearch.SearchValue="{Binding ElementName=searchBox, Path=Text, UpdateSourceTrigger=PropertyChanged}" 
          AlternatingRowBackground="Gainsboro" AlternationCount="2" HorizontalAlignment="Stretch"
          VerticalAlignment="Stretch">
   <DataGrid.Resources>
      <local:SearchValueConverter x:Key="searchValueConverter" />
      <Style TargetType="{x:Type DataGridCell}">
         <Setter Property="local:DataGridTextSearch.IsTextMatch">
            <Setter.Value>
               <MultiBinding Converter="{StaticResource searchValueConverter}">
                  <Binding RelativeSource="{RelativeSource Self}" Path="Content.Text" />
                  <Binding RelativeSource="{RelativeSource Self}" Path="(local:DataGridTextSearch.SearchValue)" />
               </MultiBinding>
            </Setter.Value>
         </Setter>
         <Style.Triggers>
            <Trigger Property="local:DataGridTextSearch.IsTextMatch" Value="True">
               <Setter Property="Background" Value="Orange" />
            </Trigger>
         </Style.Triggers>
      </Style>
   </DataGrid.Resources>
   <DataGrid.CellStyle>
      <Style TargetType="DataGridCell" >
         <Style.Triggers>
            <Trigger Property="IsSelected" Value="True">
               <Setter Property="Background" Value="#FF007ACC"/>
               <Setter Property="Foreground" Value="White"/>
            </Trigger>
         </Style.Triggers>
      </Style>
   </DataGrid.CellStyle>
</DataGrid>

My question is;

How can I create the same binding of my DataGrid to the data set I create at run-time?

Someone has suggested that the reason is that my data does not implement INotifyCollectionChanged interface, but due to the variable nature of the data, I have to load the data into the DataGrid at run-time.

How can I bind this data to the DataGrid as a class that implements INotifyPropertyChanged if the structure of the data can change?

Thanks very much for your time.

Foi útil?

Solução

I think Blam is right. (Sorry I don't have privileges to add comments yet.) In your test code, you use an ObservableCollection, which does implement INotifyPropertyChanged. The DataGrid will pick up changes to that collection. You should consider using an ObservableCollection in your real code and updating the data through it to be picked up by the bound DataGrid, rather than directly through dataGrid.ItemsSource.

The approach in the answer on this page may help: https://stackoverflow.com/a/1581588/1082026

In the end, your code may look something like this (note, you'll have to define a class DataItem that would mirror a row in your DataSet's DataTable, specifically with the properties your DataGrid cares about):

private ObservableCollection<DataItem> dataItems= new ObservableCollection<DataItem>();
public ObservableCollection<DataItem> DataItems
{
    get { return this.dataItems; }
    set 
    { 
         this.dataItems = value; 
         base.OnPropertyChanged("DataItems");
    }
}

With this binding

<DataGrid x:Name="dataGrid" ItemsSource="{Binding TestData}".../>

And if you don't want to deal with Add() and Remove(), this would be how you set the collection:

IList<DataItem> items = BuildDataGridColumns(cultureDict).Tables[0].AsDataView();
this.DataItems = new ObservableCollection<DataItem>(items);

...

private IList<DataItem> BuildDataGridColumns(Dictionary<string, string> cultureDict,
                                     DataTable additionalDt = null)
{
    // ... here create a list of DataItems from your table, and return it.
}

Hope that helps!

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top