DataGridComboBoxColumn Binding to a List<String> - c#

I have a WPF application that contains a datagrid. The datagrid is bound to my object OrderBlock which contains a List of type Orders.
<DataGrid DataContext="{Binding OrderBlock}"
Name="dataGridOrdersGood"
ItemsSource="{Binding Orders}"
This works fine and displays nicely in my datagrid. There is one property (StatusGood) in my List though that I would like to display as a combobox where there can be only two values, "Send" or "Hold".
So I was trying to bind the combobox values to the List StatusList as shown below. Then trying to bind the actual value to my object.
public class ViewModel : INotifyPropertyChanged
{
public List<string> StatusList;
// constructor
public ViewModel()
{
StatusList = new List<string>();
StatusList.Add("Hold");
StatusList.Add("Send");
}
}
<DataGridComboBoxColumn Header="Status Good" SelectedItemBinding="{Binding StatusList}" SelectedValuePath="{Binding StatusGood}"/>
However nothing is displayed other than a empty combobox. I do not understand why at the very least my combobox is not showing the value of my object? I am providing a list so again I do not understand why it's not showing anything.
I'm new to WPF and must struggling to understand it. I have referenced but obviously not fully understand it. http://msdn.microsoft.com/en-us/library/system.windows.controls.datagridcomboboxcolumn.aspx
Any help would be great!
Thanks,
M

I have a solution, where your List is a ComboBoxItem, would this be possible?
Here is my sample XAML:
<DataGrid AutoGenerateColumns="False" Name="myGridTest">
<DataGrid.Columns>
<DataGridTextColumn Header="Text" Binding="{Binding MyText}" />
<DataGridTemplateColumn Header="Combobox">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox SelectedIndex="0" ItemsSource="{Binding ComboList}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
My C#-Class
public class Test
{
private string _MyText;
private IList<ComboBoxItem> _ComboList;
public Test()
{
_MyText = "Test 123";
_ComboList = new List<ComboBoxItem>();
_ComboList.Add(new ComboBoxItem() { Content = "Next", IsSelected = true });
_ComboList.Add(new ComboBoxItem() { Content = "Prev." });
}
public IList<ComboBoxItem> ComboList
{
get { return _ComboList; }
set { _ComboList = value; }
}
public string MyText
{
get { return _MyText; }
set { _MyText = value; }
}
}
And for Testing:
List<Test> cList = new List<Test>();
cList.Add(new Test());
cList.Add(new Test());
cList.Add(new Test());
cList.Add(new Test());
cList.Add(new Test());
myGridTest.ItemsSource = cList;
I hope this help you...

It looks like DataGridComboBoxColumn->SelectedItemBinding has to be in your case:
SelectedItemBinding="{Binding StatusGood}"
and you have to set also ItemsSource property of the DataGridComboBoxColumn and modify your ViewModel for providing combo values to use property(StatusList) instead of field.
VM:
public class ViewModel
{
public List<string> StatusList { get; set; }
// constructor
public ViewModel()
{
StatusList = new List<string>();
StatusList.Add("Hold");
StatusList.Add("Send");
}
}
XAML:
<DataGrid.Resources>
<local:ViewModel x:Key="ComboItems" />
</DataGrid.Resources>
<DataGridComboBoxColumn SelectedItemBinding="{Binding StatusGood}" ItemsSource="{Binding Path=StatusList, Source={StaticResource ComboItems}}" >

Related

DataGridComboBoxColumn different ItemsSource for different rows

Here the question similar to my question is asked, but I did not find the solution there.
My Question : How to bind different data(say Lists) to the "DataGridComboBoxColumn" for each ComboBox in a different rows. Here is the code I tried
XAML:
<Grid>
<DataGrid x:Name="dg_TimeTable" AutoGenerateColumns="False" Margin="0,0,0,97" ColumnWidth="*">
<DataGrid.Columns>
<DataGridTextColumn IsReadOnly="True" Binding="{Binding CLASS}" Header="CLASS" />
<DataGridComboBoxColumn Header="PERIOD" x:Name="gPeriods" SelectedValueBinding="{Binding PERIOD, Mode=TwoWay}" DisplayMemberPath="{Binding PERIOD}" />
<DataGridComboBoxColumn Header="TEACHERS" x:Name="gTeachers" SelectedValueBinding="{Binding TEACHER, Mode=TwoWay}" DisplayMemberPath="{Binding TEACHER}" />
<DataGridComboBoxColumn Header="SUBJECTS" x:Name="gSubjects" SelectedValueBinding="{Binding SUBJECT, Mode=TwoWay}" DisplayMemberPath="{Binding SUBJECT}"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
.cs
using System.Collections.ObjectModel; // For ObservableCollection
public partial class MainWindow : Window
{
ObservableCollection<string> listTeachersSix = null;
ObservableCollection<string> listTeachersSeven = null;
ObservableCollection<string> listTeachersEight = null;
ObservableCollection<string> listTeachersNine = null;
ObservableCollection<string> listTeachersTen = null;
ObservableCollection<string> listSubjects = null;
ObservableCollection<int> listPeriods = null;
public MainWindow()
{
InitializeComponent();
listTeachersSix = new ObservableCollection<string>();
listTeachersSeven = new ObservableCollection<string>();
listTeachersEight = new ObservableCollection<string>();
listTeachersNine = new ObservableCollection<string>();
listTeachersTen = new ObservableCollection<string>();
listSubjects = new ObservableCollection<string>();
listPeriods = new ObservableCollection<int>();
listTeachersSix.Add("Vijay");
listTeachersSix.Add("Naveen");
listTeachersSix.Add("Gopal");
listTeachersSix.Add("Somesh");
listTeachersSeven.Add("Raj");
listTeachersSeven.Add("Rama Krishna");
listTeachersSeven.Add("Rakesh");
listTeachersSeven.Add("Ram Babu");
listTeachersEight.Add("Murali");
listTeachersEight.Add("Ritesh");
listTeachersEight.Add("Nagesh");
listTeachersEight.Add("Tarun");
listTeachersNine.Add("Bhaskar");
listTeachersNine.Add("Babji");
listTeachersNine.Add("Bhanu");
listTeachersNine.Add("Balaji");
listTeachersTen.Add("Lal");
listTeachersTen.Add("Mohan");
listTeachersTen.Add("Raj Sekhar");
listTeachersTen.Add("Sunil");
for (int i = 0; i <= 8; i++)
listPeriods.Add(i);
listSubjects.Add("Maths");
listSubjects.Add("Physics");
listSubjects.Add("Social");
listSubjects.Add("English");
listSubjects.Add("Hindi");
listSubjects.Add("Telugu");
List<Info> listTimeTable = new List<Info>()
{
new Info () { CLASS="6", PERIOD=1, TEACHER="Vijay", SUBJECT="Maths" },
new Info () { CLASS="7", PERIOD=5, TEACHER="Raj", SUBJECT="Physics" },
new Info () { CLASS="8", PERIOD=7, TEACHER="Murali", SUBJECT="Social" },
new Info () { CLASS="10", PERIOD=4, TEACHER="Mohan", SUBJECT="English" },
new Info () { CLASS="6", PERIOD=8, TEACHER="Naveen", SUBJECT="Maths" },
new Info () { CLASS="9", PERIOD=3, TEACHER="Bhaskar", SUBJECT="Hindi" },
new Info () { CLASS="8", PERIOD=6, TEACHER="Ritesh", SUBJECT="English" },
new Info () { CLASS="10", PERIOD=2, TEACHER="Lal", SUBJECT="Social" }
};
dg_TimeTable.ItemsSource = listTimeTable;
gPeriods.ItemsSource = listPeriods;
gSubjects.ItemsSource = listSubjects;
gTeachers.ItemsSource = listTeachersSix;
}
}
public class Info
{
public string CLASS { get; set; }
public int PERIOD { get; set; }
public string SUBJECT { get; set; }
public string TEACHER { get; set; }
}
when I run this code, the output is as below.
As you all see in my code there are different teachers for different classes. When I click on say 9th class,
"listTeachersNine" should be added to the "gTeachers.ItemsSource". But if I do so
gTeachers.ItemsSource = listTeachersNine;
all the other rows are effecting. How can I do this without change in the other rows. Please give me some idea... Thanks in advance
UPDATE :
Even though I tried this below code
private void dg_TimeTable_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
int num = (sender as DataGrid).SelectedIndex;
try
{
if (num == 0)
{
//listTeachersSix.Clear();
//listTeachersSix.Add("Vijay");
//listTeachersSix.Add("Naveen");
//listTeachersSix.Add("Gopal");
//listTeachersSix.Add("Somesh");
gTeachers.ItemsSource = listTeachersSix;
}
else if (num == 1)
{
//listTeachersSix.Clear();
//listTeachersSix.Add("Raj");
//listTeachersSix.Add("Rama Krishna");
//listTeachersSix.Add("Rakesh");
//listTeachersSix.Add("Ram Babu");
gTeachers.ItemsSource = listTeachersSeven;
}
else if (num == 2)
{
//listTeachersSix.Clear();
//listTeachersSix.Add("Murali");
//listTeachersSix.Add("Ritesh");
//listTeachersSix.Add("Nagesh");
//listTeachersSix.Add("Tarun");
gTeachers.ItemsSource = listTeachersEight;
}
}
I tried both commented part and uncommented part but its no use. When I run my application starting it shows as above first diagram. But when click on particular row, all the other rows data are vanishing. But the thing is, it is updating the new teachers data. Look at the below two pictures.
So without changing the other rows can I update the row I wanted.....
There's a few ways I can think to do this.
If you don't care about strict MVVM design, you could use a IValueConverter, pass it your CLASS, and have the converter figure out which list to return. Something along the lines of
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
string key = value as string;
switch (key)
{
case "1":
return SomethingStatic.TeacherList1;
case "2":
return SomethingStatic.TeacherList2;
...
}
}
If you want to make it dynamic and avoid hardcoded list references in your Converter, you could use an IMultiValueConverter and pass it the variable arrays as another bound value and tweak the code to simply find the right ItemsSource from the array passed in from the other bound values.
Note that to use either of these, you'll probably have to switch from a DataGridComboBoxColumn to a DataGridTemplateColumn because the bindings won't work correctly from the ComboBoxColumn.
<DataGridTemplateColumn Header="TEACHERS">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding CLASS, Converter={StaticResource TestConverter}}"
SelectedItem="{Binding TEACHER}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Another alternate solution would be to add the list of ValidTeachers to item for each DataRow, in your case the Info object.
public class Info
{
public string CLASS { get; set; }
public int PERIOD { get; set; }
public string SUBJECT { get; set; }
public string TEACHER { get; set; }
public List<string> ValidTeachers { get; set; }
}
You'd also need a Change Event so whenever CLASS changes, the ValidTeachers array gets updated.
I'm sure there's other options that might be cleaner, but if you're looking for something simple and easy I'd recommend one of these.
Check out the answer here by Vincent Sibal - MSFT:
This should help you with setting the ItemsSource of one column in a certain row based on the selection in another column of that same row. It is using styles to set the ItemsSource every time you click on a ComboBox to edit the value.
Here is the example given at the above site, in case the link is removed in the future:
The example is if I have a DataGrid, and I want the selection in a column labeled Current Category to affect the options in the DataGridComboBoxColumn called Current Product.
The items in the ProductsInCategory collection/list serve as the selectable values for the Current Product column. The items in this list are set in the setter for the CurrentCategory, as seen below:
public int CurrentCategory
{
get { return _currentCategory; }
set
{
_currentCategory = value;
ProductsInCategory = DBAccess.GetProductsInCategory(_currentCategory).Tables["Products"].DefaultView;
OnPropertyChanged("CurrentCategory");
}
}
Below is the xaml that will be used to hook up the Current Product ItemsSource anew whenever the CurrentCategory selection is changed.
<dg:DataGridComboBoxColumn Header="Current Product"
SelectedValueBinding="{Binding Path=CurrentProduct}"
SelectedValuePath="ProductID"
DisplayMemberPath="ProductName">
<dg:DataGridComboBoxColumn.ElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding Path=ProductsInCategory}" />
</Style>
</dg:DataGridComboBoxColumn.ElementStyle>
<dg:DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding Path=ProductsInCategory}" />
</Style>
</dg:DataGridComboBoxColumn.EditingElementStyle>
</dg:DataGridComboBoxColumn>
Refer the link msdn link
I cannot devote much time on it now. I took your original code and added to it. Its not complete but it will save some effort.
XAML
<Grid>
<DataGrid x:Name="dg_TimeTable" AutoGenerateColumns="False" Margin="0,0,0,97" ColumnWidth="*" PreparingCellForEdit="dg_TimeTable_PreparingCellForEdit">
<DataGrid.Columns>
<DataGridTextColumn IsReadOnly="True" Binding="{Binding CLASS}" Header="CLASS" />
<DataGridComboBoxColumn Header="PERIOD" x:Name="gPeriods" SelectedValueBinding="{Binding PERIOD, Mode=TwoWay}" DisplayMemberPath="{Binding PERIOD}" />
<DataGridComboBoxColumn Header="TEACHERS" x:Name="gTeachers" SelectedValueBinding="{Binding TEACHER, Mode=TwoWay}" DisplayMemberPath="{Binding TEACHER}" />
<DataGridTemplateColumn Header="TEACHERS" x:Name="colTeacherList" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=TEACHER, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox Name="cmbTeacherList" SelectedItem="{Binding myItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
<DataGridComboBoxColumn Header="SUBJECTS" x:Name="gSubjects" SelectedValueBinding="{Binding SUBJECT, Mode=TwoWay}" DisplayMemberPath="{Binding SUBJECT}"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
C# code
private void dg_TimeTable_PreparingCellForEdit(object sender, DataGridPreparingCellForEditEventArgs e)
{
int rowIndex = dg_TimeTable.SelectedIndex;
if (e.Column == colTeacherList)
{
FrameworkElement element = e.EditingElement;
ComboBox cb = GetVisualChild<ComboBox>(element);
if (cb != null)
{
switch(dg_TimeTable.SelectedIndex)
{
case 1:
cb.ItemsSource = listTeachersSeven;
break;
case 2:
cb.ItemsSource = listTeachersEight;
break;
default:
cb.ItemsSource = listTeachersSix;
break;
}
}
}
}
static T GetVisualChild<T>(Visual parent) where T : Visual
{
T child = default(T);
int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < numVisuals; i++)
{
Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
child = v as T;
if (child == null)
{
child = GetVisualChild<T>(v);
}
if (child != null)
{
break;
}
}
return child;
}

Bind ObservableCollection to ComboBox in DataGrid is not working

I have ready many articles which covers binding Observable Collection to ComboBox but I stil can't figure it out why my collection isn't bindng to ComboBox placed in DataGrid.
My Model
class DDV
{
public DDV(int ID, string Naziv)
{
_ID = ID;
_Naziv = Naziv;
}
private int _ID;
public int ID
{
get { return _ID; }
set { _ID = value; }
}
private string _Naziv;
public string Naziv
{
get { return _Naziv; }
set { _Naziv = value; }
}
My ViewModel:
class ArtikliStoritveViewModel : INotifyPropertyChanged
{
public ArtikliStoritveViewModel()
{
DDVData.Add(new DDV(1, "Ceka"));
DDVData.Add(new DDV(2, "Zeka"));
}
private ObservableCollection<DDV> _DDVData = new ObservableCollection<DDV>();
public ObservableCollection<DDV> DDVData
{
get
{
return this._DDVData;
}
set
{
_DDVData = value;
}
}
DataContext:
<Window.DataContext>
<local:ArtikliStoritveViewModel/>
</Window.DataContext>
Binding:
<DataGridTemplateColumn Header="Test">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox
x:Name="cmbDDV"
ItemsSource="{Binding DDVData}"
DisplayMemberPath="Naziv"
/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
I have observable collection in View model:
private ObservableCollection<DDV> _DDVData = new ObservableCollection<DDV>();
public ObservableCollection<DDV> DDVData
{
get
{
return this._DDVData;
}
set
{
_DDVData = value;
}
}
My DataGrid Bind to tihs View Model:
<DataGrid ItemsSource="{Binding Path=ArtikliStoritveData}
In constructor in View model I bind to collection:
DDV _ddv;
public ArtikliStoritveViewModel()
{
_ddv = new DDV { ID = 1, Naziv = "Ceka" };
DDVData.Add(_ddv);
}
So everything must stay in this View Model.
What else I have to do to make this work. Currently nothing is binding.
Regards,
Igor
Your mistake is in your data model. What is available to your DataTemplate is an instance of your DDV class and that has no collection property named DDVData to data bind to. Instead, you need to add a collection to your DDV class that you can data bind to the ComboBox in each row of the DataGrid and then data bind the collection property named DDVData from the view model to the DataGrid.ItemsSource property:
<DataGrid ItemsSource="{Binding CollectionPropertyInViewModel}">
...
<DataGridTemplateColumn Header="Test">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox x:Name="cmbDDV"
ItemsSource="{Binding CollectionPropertyInModelClass}"
DisplayMemberPath="Naziv" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
...
</DataGrid>
Incidentally, if you had looked in your Output Window in Visual Studio, you should have seen some errors saying something like there is no property named DDVData found in object DDV or something like that... helpful clues.
UPDATE >>>
I updated the code above to make it clearer. With your information that you just provided, you'd need to do this:
<DataGrid ItemsSource="{Binding DDVData}">
...
<DataGridTemplateColumn Header="Test">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox x:Name="cmbDDV"
ItemsSource="{Binding ArtikliStoritveData}"
DisplayMemberPath="Naziv" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
...
</DataGrid>
This will work when:
The DataGrid is in the Window that has the ArtikliStoritveViewModel instance set as its DataContext
The DDVData property is in the ArtikliStoritveViewModel
The DDV class has a collection property declared in it named ArtikliStoritveData
If that is not the case, then this won't work. You said I have some other Observable Collection in Model View, so I can not change it to DDVDData in DDV model... I have no idea what you mean by Model View, but if you set the Window.DataContext to an instance of you ArtikliStoritveViewModel, the that is what it has access to. So, you'll either need to add the collection into the DDV class, or the ArtikliStoritveViewModel class.

Sort ObservableCollection bound to DataGrid in MVVM

I have a DataGrid that I'm binding to an ObservableCollection in my view model and I need to be able to sort the collection when the DataGrid is sorted to so I can use this sorted order elsewhere. I'm currently using a wrapper on the ObvservableCollection to support sorting. When the DataGrid is sorted it only sorts the displayed data and not the underlying data in the collection. The data consists of one integer column and one string column and needs to support ascending and descending sort on both. I also want to maintain the same usage as the standard DataGrid sort where you click a column header and it toggles between ascending and descending sort. I'm relatively new to WPF so I don't know all the ins and outs of data and command binding, but I would think there would be a way to accomplish what I want to do. Here is a sample xaml to illustrate my view set up.
<DataGrid ItemsSource="{Binding mySource}"
Name="myDataGrid"
CanUserResizeRows="False"
AutoGenerateColumns="False"
HeadersVisibility="Column" >
<DataGrid.Columns>
<DataGridTemplateColumn Header="Header 1" CanUserSort="True" SortMemberPath="firstValue">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding firstValue}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Header 2" Width="*" CanUserSort="True" SortMemberPath="secondValue">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding secondValue}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
The source data is of a type something like:
public class myType
{
public int firstValue { get; set; }
public string secondValue { get; set; }
// some functions and variables...
}
Now, like I said above, I need access to the items in the collection in their sorted order, but it does not need to specifically be an ObservableCollection. As long as I can iterate through the items in the collection in whatever the current order is when I access them, all is good. I was thinking maybe a ListCollectionView or something. I also don't want the collection to re-sort itself when new items are added to the collection. Any new items should just be added to the end of the collection as would normally happen.
Any ideas?
The DataGrid uses an underlying ICollectionView based on the DataSource, so if you directly bind a ICollectionView you can access the sorted values as the DataGrid will directly change the ICollectionView when sorting.
Small Example:
Code:
public partial class MainWindow : Window
{
public MainWindow()
{
// dummy data source / Your ObservableCollection
var yourObservableCollection = Enumerable.Range(0, 30)
.Select(i => new MyType { FirstValue = i, SecondValue = i.ToString() });
// Create CollectionView based on the data you want to show
MySource = CollectionViewSource.GetDefaultView(yourObservableCollection);
InitializeComponent();
}
public ICollectionView MySource { get; set; }
private void Button_Click_1(object sender, RoutedEventArgs e)
{
foreach (var item in MySource.OfType<MyType>())
{
Console.WriteLine("MyType - First: {0}, Second: {1}",
item.FirstValue,
item.SecondValue);
}
}
}
public class MyType
{
public int FirstValue { get; set; }
public string SecondValue { get; set; }
}
Xaml:
<Window x:Class="WpfApplication8.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"`enter code here` Name="UI" Width="262" Height="318">
<Grid DataContext="{Binding ElementName=UI}">
<DataGrid Name="myDataGrid"
ItemsSource="{Binding MySource}"
CanUserSortColumns="True"
Margin="0,0,0,37" />
<Button Content="Print To Output Window"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Margin="10,0,0,10"
Width="144"
Click="Button_Click_1"/>
</Grid>
</Window>
I know this is an old question but I struggled to find an answer when I had a similar issue where I wanted to print/export the data in the same order it was displayed on the screen. Although #sa_ddam213 answer is correct it needs a bit of adjusting to fit the MVVM pattern, so hopefully this answer is of use to somebody else. To achieve this first add to your View Model an ICollectionView (I believe this is the same data structure used by the UI):
private ObservableCollection<yourDataType> tableData = new ObservableCollection<yourDataType>(); // The DataGridknow was originally bound to this
private ICollectionView tableDataWrapper;
Then add a new Getter/Setter for your ICollectionView:
public ICollectionView TableDataWrapper
{
get { return this.tableDataWrapper; }
set
{
this.tableDataWrapper = value;
OnPropertyChanged("TableDataWrapper");
}
}
And in your original TableData Setter add a line to set the wrapper each time the table data is set:
public ObservableCollection<yourDataType> TableData
{
get { return this.tableData; }
set
{
this.tableData = value;
this.TableDataWrapper = CollectionViewSource.GetDefaultView(tableData); // Add this
OnPropertyChanged("TableData");
}
}
Now update the DataGrid's Bindings so it is bound to TableDataWrapper rather than TableData
Now to access the data in the sorted order:
this.TableDataWrapper.Cast<yourDataType>().ToList<yourDataType>()
or if you want it as an ObservableCollection:
new ObservableCollection( this.TableDataWrapper.Cast<yourDataType>().ToList<yourDataType>() )
You can use ICollectionView to sort an existing collection. It is found under System.ComponentModel
The code goes like this
var collectionView = CollectionViewSource.GetDefaultView(ObservableCollection_Name);
collectionView.SortDescriptions.Add(new SortDescription("Your Property", ListSortDirection.Descending));
In your GridView or ListView you can bind the existing ObservableCollection. No need to change.
I've tried the solution of John Cummings & stuicidle. DataGrid in XAML does not show anything. Because the ItemsSource of the DataGrid is not ObservableCollection.
In ViewModel:
public ICollectionView DataGridWraper
{
get { return _dataGridWraper; }
set
{
if (_dataGridWraper != value)
{
_dataGridWraper = value;
OnPropertyChanged(nameof(DataGridWraper));
}
}
}
public ObservableCollection<Customer> Customers
{
get { return _customers; }
set
{
if (_customers != value)
{
_customers = value;
DataGridWraper = CollectionViewSource.GetDefaultView(_customer);
OnPropertyChanged(nameof(Customers));
}
}
}
In XAML:
<DataGrid
ItemsSource="{Binding DataGridWraper, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="*"/>
</DataGrid.Columns>
</DataGrid>

DataGrid Showing Blank Lines when bound to an ObservableCollection<Object>

I have a simple DataGrid which I am binding to a ObservableCollection and its producing black small lines in the Grid with no Data Visible. I am using ObservableCollection as I have the collection being built in RunTime using Reflection.
I am doing something like this
XAML
<DataGrid ItemsSource="{Binding Data}" />
C#
public ObservableCollection<object> Data
{
get { return _Data; }
set {
this._deals = value;
this.NotifyPropertyChanged("Deals");
}
}
public Run()
{
this.Data = CreateData(typeof(MyRecordClass)) //'MyRecordClass' needs to be passed at runtime
}
public ObservableCollection<Object> CreateData(Type RecordType)
{
ObservableCollection<Object> data = new ObservableCollection<object>();
var record = Activator.CreateInstance(RecordType);
// Logic to load the record with Data
data.Add(record);
return data;
}
Is there a way in which I can make the DataGrid read an ObservableCollection without specifying the ColumnNames or create a ObservableCollection object in the CreateData function ?
Your collection should have public properties, so datagrid could bind columns to it.
If you use collection type of Object than you have no properies for binding, so the empty rows will be displayed.
Here is example for you:
public partial class MainWindow : Window
{
public ObservableCollection dataSource;
public MainWindow()
{
InitializeComponent();
this.dataSource = new ObservableCollection<SomeDataSource>();
this.dataSource.Add(new SomeDataSource { Field = "123" });
this.dataSource.Add(new SomeDataSource { Field = "1234" });
this.dataSource.Add(new SomeDataSource { Field = "12345" });
this.dataGrid1.ItemsSource = this.dataSource;
}
}
public class SomeDataSource
{
public string Field {get;set;}
}
<DataGrid AutoGenerateColumns="False" Height="253" HorizontalAlignment="Left" Margin="27,24,0,0" Name="dataGrid1" VerticalAlignment="Top" Width="448">
<DataGrid.Columns>
<DataGridTextColumn Header="First" Binding="{Binding Path=Field, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataGrid.Columns>
</DataGrid>

Datagrid binding in WPF

I know this has been asked already but I have done almost everything what is suggested by developers.
<DataGrid x:Name="Imported" VerticalAlignment="Top"
DataContext="{Binding Source=list}"
AutoGenerateColumns="False" CanUserResizeColumns="True">
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding Path=ID}"/>
<DataGridTextColumn Header="Date" Binding="{Binding Path=Date}"/>
</DataGrid.Columns>
</DataGrid>
I am trying to show this in modal dialog box and populating the license list in the constructor of the modal dialog box.
But still nothing is getting populated inside the DataGrid.
Constructor code:
public diagboxclass()
{
List<object> list = new List<object>();
list = GetObjectList();
}
public class object
{
string id;
DateTime date;
public string ID
{
get { return id; }
set { id = value; }
}
public DateTime Date
{
get { return date; }
set { date = value; }
}
}
Do you guys think something to do with the object list?
PLEASE do not use object as a class name:
public class MyObject //better to choose an appropriate name
{
string id;
DateTime date;
public string ID
{
get { return id; }
set { id = value; }
}
public DateTime Date
{
get { return date; }
set { date = value; }
}
}
You should implement INotifyPropertyChanged for this class and of course call it on the Property setter. Otherwise changes are not reflected in your ui.
Your Viewmodel class/ dialogbox class should have a Property of your MyObject list. ObservableCollection<MyObject> is the way to go:
public ObservableCollection<MyObject> MyList
{
get...
set...
}
In your xaml you should set the Itemssource to your collection of MyObject. (the Datacontext have to be your dialogbox class!)
<DataGrid ItemsSource="{Binding Source=MyList}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding ID}"/>
<DataGridTextColumn Header="Date" Binding="{Binding Date}"/>
</DataGrid.Columns>
</DataGrid>
Without seeing said object list, I believe you should be binding to the DataGrid's ItemsSource property, not its DataContext.
<DataGrid x:Name="Imported" VerticalAlignment="Top"
ItemsSource="{Binding Source=list}"
AutoGenerateColumns="False" CanUserResizeColumns="True">
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding ID}"/>
<DataGridTextColumn Header="Date" Binding="{Binding Date}"/>
</DataGrid.Columns>
</DataGrid>
(This assumes that the element [UserControl, etc.] that contains the DataGrid has its DataContext bound to an object that contains the list collection. The DataGrid is derived from ItemsControl, which relies on its ItemsSource property to define the collection it binds its rows to. Hence, if list isn't a property of an object bound to your control's DataContext, you might need to set both DataContext={Binding list} and ItemsSource={Binding list} on the DataGrid).
Try to do this in the behind code:
public diagboxclass()
{
List<object> list = new List<object>();
list = GetObjectList();
Imported.ItemsSource = null;
Imported.ItemsSource = list;
}
Also be sure your list is effectively populated and as mentioned by #Blindmeis, never use words that already are given a function in C#.

Categories