I already spent hours on this, and similar topics did not help. :(
I've got an object of type "Chart" which contains a List "LineItems".
I want to bind LineItems programmatically to a DataGrid in an UserControl.
Usercontrol XAML:
<DataGrid Name="myData" AutoGenerateColumns="True">
Usercontrol Code behind:
public void SetItemSource(ChartingBase.Chart chart)
{
//DataGrid.ItemsSource = chart.LineItems; // working!
// this is not working:
this.DataContext = chart;
Binding b = new Binding( "LineItems" );
b.Mode = BindingMode.TwoWay;
b.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
myData.SetBinding( DataGrid.ItemsSourceProperty, b );
}
Setting just the ItemsSource works. Creating the binding manually does not work and I have no clue what else I could try. Thanks!
Try
BindingOperations.SetBinding(myData, DataGrid.ItemsSourceProperty, new Binding("LineItems") { Source = chart });
In WPF, it is customary to put your data into an ObservableCollection<T> collection and data bind that to the DataGrid.ItemsSource property. Then you can fill or manipulate the collection in code and the UI will update automatically. Try this:
<DataGrid Name="myData" ItemsSource="{Binding Items}" AutoGenerateColumns="True">
...
public void SetItemSource(ChartingBase.Chart chart)
{
this.DataContext = chart;
Items = new ObservableCollection<YourDataType>();
foreach (SomeDataType dataType in chart.SomeCollection)
{
Items.Add(new YourDataType(dataType.SomeProperty, ...));
}
}
Related
In my window I have ListBox that contain collection of usercontrols like:
<ListBox ItemsSource="{Binding UserControls}">
Inside the user control class I have DataGrid that bind to datatable:
<DataGrid ItemsSource="{Binding TableResult}"/>
From the window's viewmodel I'm adding dynamiclly more usercontrols to the ListBox, like:
void AddUserControl()
{
MyUserControl uc = new MyUserControl
{
DataContext = this
};
UserControls.Add(uc);
}
For now all the usercontrols bind to the same table: TableResult
But what I what is a new DataTable for each usercontrol.
I have tried like:
void AddUserControl()
{
MyUserControl uc = new MyUserControl
{
DataContext = this
};
DataTable dt = new DataTable();
uc.MyGridView.ItemsSource = dt.DefaultView;
UserControls.Add(uc);
}
but now this part will be missing for the new datatable:
DataTable dt;
public DataTable Dt
{
get { return dt; }
set
{
dt = value;
RaisePropertyChanged("Dt");
}
}
Note: I have only one viewmodel for the window, therefore the datacontext of each usercontrol is the same viewmodel
Any suggestions for this secnario? I mean how do I bind a new datatable for each new usercontrol
You shouldn't bind to an IEnumerable<UserControl>. Referencing UI elements or controls in a view model breaks the MVVM pattern.
What you should do is to create a class to which you add the DataTable property and then bind to an IEnumerable<YourClass>. The actual UserControl should be defined in the ItemTemplate of the ListBox in the view:
<ListBox ItemsSource="{Binding DataObjects}">
<ListBox.ItemTemplate>
<local:MyUserControl />
</ListBox.ItemTemplate>
</ListBox>
The root element in the ItemTemplate inherits its DataContext from the current item in the ListBox which means that you can bind directly to any public property of YourClass in MyUserControl:
<DataGrid ItemsSource="{Binding TableProperty}"/>
Hi I am trying to loop through rows in a datagrid
If I use:
PagedCollectionView pgView = dataGrid.ItemsSource as PagedCollectionView;
foreach (var item in pgView.)
{}
I get the item as entity and I can't figure out how to cast that to some meaningfull data
can anyone help me there ?
if I use:
IEnumerable list = dataGrid.ItemsSource as IEnumerable;
foreach (var row in list)
{}
I get the same entity and the same problem...
I have looked at the following that accomplishes the task but I feel like I am
mixing data with presentation
PagedCollectionView pgView = verkefniDataGrid.ItemsSource as PagedCollectionView;
foreach (var item in pgView)
{
((CheckBox)verkefniDataGrid.CurrentColumn.GetCellContent(item)).IsChecked = true;
}
Are the any way to get to the data behind the item and set it there to true ?
You need to iterate through the DataGrid's rows, not through the items it is bound to, if you want to check a checkbox control. You would need to loop through the rows and then grab the checkbox in the proper column and set the properties on it.
But as mentioned in the comments, if the checkbox is bound to a property in the data behind the grid, then you should just be able to change that value (as long as the item exposes the INotifyPropertyChanged interface).
Edit Updated link
Using a ViewModel approach, you could define the view like this
<Grid x:Name="LayoutRoot" Background="White">
<StackPanel Orientation="Vertical">
<sdk:DataGrid AutoGenerateColumns="False" Height="151" HorizontalAlignment="Left" Margin="52,67,0,0" Name="dataGrid1" VerticalAlignment="Top" Width="190"
ItemsSource="{Binding Items}">
<sdk:DataGrid.Columns>
<sdk:DataGridCheckBoxColumn Binding="{Binding IsSelected}"/>
<sdk:DataGridTextColumn Binding="{Binding Name}"/>
</sdk:DataGrid.Columns>
</sdk:DataGrid>
<Button Content="What is selected?" Width="300" Click="Button_Click"/>
</StackPanel>
</Grid>
Then, you setup the view to be bound against a ViewModel, which contains a property of your PagedCollectionView:
public class ViewModel
{
private PagedCollectionView _items = new PagedCollectionView(
new[]
{new MyItem{Name="Item 1"},
new MyItem{Name="Item 2"},
new MyItem{Name="Item 3"},
new MyItem{Name="Item 4"} });
public PagedCollectionView Items
{
get { return _items; }
}
public string GetSelectedItems()
{
return "Selected items: " +
string.Join(",",
Items.Cast<MyItem>().Where(x => x.IsSelected).
Select(x => x.Name));
}
}
Now, since I don't know your solution that well, I put a piece of ugly code in the code-behind just to show how that the selections are tracked:
private void Button_Click(object sender, RoutedEventArgs e)
{
var viewModel = DataContext as ViewModel;
MessageBox.Show(viewModel.GetSelectedItems());
}
Connecting the View and ViewModel together is done by creating the view, the view model and then stitch them together with the DataContext property of the view.
Like this:
var view = new MyWindow();
var viewModel = new ViewModel();
view.DataContext = viewModel;
That should make the example work.
I am new to MVVM and databinding and I am having some trouble binding a gridview to a datatable dynamically. I am able to get the column headers to bind, but no data is being displayed in the grid itself.
My model simply returns a data table as the result of a SQL string passed to it.
My viewmodel just wraps the datatable and gets bound to the view.
Right now I am just trying to display the data by populating the gridview from the main window, but only the headers are being displayed.
I know there is data in the model.Results datatable though.
My viewmodel:
public class ResultsViewModel
{
private DataTable _dt;
public ResultsViewModel()
{
DataSource _ds = new DataSource();
_dt = _ds.Execute("select * from tbl_users");
}
public DataTable Results
{
get { return _dt; }
set { _dt = value; }
}
}
My code to populate the gridview from the mainwindow:
public MainWindow()
{
InitializeComponent();
ResultsView view = new ResultsView();
ResultsViewModel model = new ResultsViewModel();
GridView Grid = new GridView();
foreach (DataColumn col in model.Results.Columns)
{
Grid.Columns.Add(new GridViewColumn
{
Header = col.ColumnName,
DisplayMemberBinding = new Binding(col.ColumnName)
});
}
view._listView.View = Grid;
view.DataContext = model;
view.SetBinding(ListView.ItemsSourceProperty, new Binding());
_placeholder.Content = view;
}
The ResultsView xaml:
<UserControl x:Class="InDevReporting.Views.ResultsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<ListView x:Name="_listView" />
</Grid>
Try setting your data context to model.Results.
ie change this line:
view.DataContext = model;
to this:
view.DataContext = model.Results;
Generally you would create a dependency property on your view model and specify the binding in the XAML. The grid should be clever enough to figure out what columns to draw:
<ListView ItemsSource="{Binding Results}" />
public MainWindow()
{
InitializeComponent();
// your code to instance and populate model
this.DataContext = model;
}
public class ResultsViewModel : DependencyObject
{
public static readonly DependencyProperty ResultsProperty = DependencyProperty.Register("Results", typeof(DataTable) , typeof(ResultsViewModel));
public DataTable Results
{
get { (DataTable)GetValue(ResultsProperty); }
set { SetValue(ResultsProperty, value); }
}
}
I've tapped this out from memory, so apologies if the code isn't exactly right. The easiest way to declare a new dependency property is to use the propdp code snippet. It's a lot of syntax to memorize.
I'm completely new to WPF/XAML. I'm trying to work out XAML code to bind a DataTable to DataGrid. What I have is an instance of custom DataContainer class which implements INotifyPropertyChanged. This class has a property:
private DataTable totalsStatus = new DataTable();
public DataTable TotalsStatus
{
get { return totalsStatus; }
set
{
totalsStatus = value;
NotifyPropertyChanged("TotalsStatus");
}
}
now, in the C'tor of my MainWindow I have this, which works like a charm:
Binding b = new Binding();
b.Source = DataContainer;
b.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
b.Path = new PropertyPath("TotalsStatus");
DataGridMain.SetBinding(DataGrid.ItemsSourceProperty, b);
How do I make this binding in XAML?
You need to use an objectdataprovider.
<ObjectDataProvider x:Key="yourdataproviderclass"
ObjectType="{x:Type local:yourdataproviderclass}" />
<ObjectDataProvider x:Key="dtable"
ObjectInstance="{StaticResource yourdataproviderclass}"
MethodName="GetTable"/> <!--here would be the method that returns your datasource-->
Then you can bind it to your datagrid in XAML with
<DataGrid ItemsSource="{Binding Source={StaticResource dtable}}" ></DataGrid>
There are different ways to do bindings in xaml though, so play around with it a bit.
I have created an ObservableCollection in the code behind of a user control. It is created when the window loads:
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
Entities db = new Entities();
ObservableCollection<Image> _imageCollection =
new ObservableCollection<Image>();
IEnumerable<library> libraryQuery =
from c in db.ElectricalLibraries
select c;
foreach (ElectricalLibrary c in libraryQuery)
{
Image finalImage = new Image();
finalImage.Width = 80;
BitmapImage logo = new BitmapImage();
logo.BeginInit();
logo.UriSource = new Uri(c.url);
logo.EndInit();
finalImage.Source = logo;
_imageCollection.Add(finalImage);
}
}
I need to get the ObservableCollection of images which are created based on the url saved in a database. But I need a ListView or other ItemsControl to bind to it in XAML file like this:
But I can't figure it out how to pass the ObservableCollection to the ItemsSource of that control. I tried to create a class and then create an instance of a class in xaml file but it did not work. Should I create a static resource somehow>
Any help will be greatly appreciated.
Firstly, the ObservableCollection is a local variable. What you need to do is have it as a private global variable and expose it with a public property. You can use the INotifyPropertyChanged interface to have the image data update automagically when the actual collection itself changes.
In your XAML, you then need to set the DataContext to self, and you can then directly bind your public property to the ItemsSource. You may want to use an ItemTemplate for displaying the items in a custom manner.
Cheers,
Adam
Example as requested:
In C#:
public MyWindowClass
{
public ObservableCollection<image> MyImageCollection
{
get;
set;
}
}
In XAML:
<UserControl
...
DataContext="{Binding RelativeSource={RelativeSource Self}}">
...
<ListBox ItemsSource="{Binding MyImageCollection}" ItemTemplate="*yourtemplateresource*" />
...
</UserControl>
Now, the reason that I mentioned using INotifyPropertyChanged is that if you try:
MyImageCollection = new ObservableCollection<image>();
The items in the listbox will not automatically update. With an ObservableCollection, however, you do not need to implement INotifyPropertyChanged for basic addition and removal of list items.
You have to set the DataContext of the UserControl to your collection:
DataContext = _imageCollection
You can do that in the UserControl_Loaded() method.
Next you need to bind the ItemsSource of the ListView in the XAML:
<ListView ItemsSource="{Binding}"/>
The {Binding} is equivalent to {Binding .} which binds to the DataContext of the UserControl. If you need "more stuff" in your DataContext you can instead create a class like this:
class ViewModel : INotifyPropertyChanged {
public ObservableCollection Images { get { ... } }
...
}
Use this class for the DataContext:
DataContext = new ViewModel();
And replace the binding to bind to the Images property:
<ListView ItemsSource="{Binding Images}"/>
Then you can add another property to ViewModel:
class ViewModel : INotifyPropertyChanged {
public ObservableCollection Images { get { ... } }
public String Message { get { ... } set { ... } }
...
}
And bind it to a control:
<TextBlock Text="{Binding Message}"/>
Remember to fire the PropertyChanged event when the Message property is changed in ViewModel. This will update the UI when view-model properties are changed by code.