EDIT
I've deviated from the methods illustrated here (which I was unable to get to work).
Binding data worked when I implemented MVVM as per this question
ORIGINAL QUESTION
I followed a tutorial (which I've since lost the link to) to create a data binding for my DataGrid.
The process involved creating a data source from my model which allowed me to drag a DataGrid onto my Window.
The DataGrid renders empty on the window when I run it and I know for a fact there is data that needs to go into it.
Here's the code:
<Page.Resources>
<CollectionViewSource x:Key="campaignViewSource" d:DesignSource="{d:DesignInstance {x:Type Models:Campaign}, CreateList=True}"/>
</Page.Resources>
<DataGrid x:Name="campaignDataGrid" AutoGenerateColumns="False" EnableRowVirtualization="True" ItemsSource="{Binding}" Grid.Row="1" RowDetailsVisibilityMode="VisibleWhenSelected">
<DataGrid.Columns>
<DataGridTextColumn x:Name="clientColumn" Binding="{Binding Client}" Header="Client" Width="SizeToHeader"/>
<DataGridTemplateColumn x:Name="dateSentColumn" Header="Date Sent" Width="SizeToHeader">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<DatePicker SelectedDate="{Binding DateSent, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn x:Name="idColumn" Binding="{Binding Id}" Header="#" Width="SizeToHeader"/>
<DataGridTextColumn x:Name="nameColumn" Binding="{Binding Name}" Header="Name" Width="SizeToHeader"/>
<DataGridTextColumn x:Name="emailAddressColumn" Binding="{Binding EmailAddress}" Header="Email Address" Width="SizeToHeader"/>
</DataGrid.Columns>
</DataGrid>
According to the tutorial I built this from, there's nothing more that I need to do to make this work. So what have I missed?
How should I proceed?
Try to bind the ItemsSource property to your CollectionViewSource:
<DataGrid x:Name="campaignDataGrid" AutoGenerateColumns="False" EnableRowVirtualization="True"
ItemsSource="{Binding Source={StaticResource campaignViewSource}}" Grid.Row="1" RowDetailsVisibilityMode="VisibleWhenSelected">
You also need to set the Source property of the CollectionViewSource to some source collection:
var cvs = this.Resources["campaignViewSource"] as CollectionViewSource;
cvs.Source = new List<YourDataObject> { new YourDataObject(), new YourDataObject() };
The drag-and-drop approach is really no good way of either doing or learning something. You should learn XAML and MVVM if you want to become a successful WPF developer.
Related
I have a pretty straight forward application containing a DataGrid. For the different columns I use different Types. So for one column I use a DatePicker (included via DataGridTemplateColumn).
<DataGrid x:Name="tblTopics"
ItemsSource="{Binding Topics}"
AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridComboBoxColumn Header="Typ" Width="100" SelectedItemBinding="{Binding Type}" ItemsSource="{Binding Source={local:EnumBindingSource {x:Type local:TopicType}}}"/>
<DataGridTextColumn Header="Titel" Width="150" Binding="{Binding Subject}"/>
<DataGridTextColumn Header="Beschrieb" Width="*" Binding="{Binding Description}"/>
<DataGridTemplateColumn Header="Wann">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<DatePicker SelectedDate="{Binding DueDate}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Wer" Width="100" Binding="{Binding ResponsiblePerson}"/>
</DataGrid.Columns>
</DataGrid>
Everything is working as intended. However, I have two questions:
How can I remove the DatePicker object in the empty/new row?
Assuming an additional ComboBoxColumn, how would I bind its values to the available items in a ListView (on the same window)?
Regarding the second questions:
In the "MainWindow.xaml.cs" I have an ObservableCollection 'Participants' which is bound to a ListView 'lstViewParticipants'. Based on some user settings, the available participants are adjusted. My goal is to update the available items in the ComboBoxColumn based on the currently visible items in the mentioned ListView. However, I am new to c# and, thus, struggling with the whole binding topic. Any idea/guidance is appreciated
I am learning to use ReactiveUI in WPF. I have an application that has an IObservableCollection which I am binding to a DataGrid.
<DataGrid Grid.Row="3" Grid.ColumnSpan="2" AutoGenerateColumns="False" ScrollViewer.VerticalScrollBarVisibility="Visible" x:Name="validationResults" HorizontalAlignment="Stretch" IsReadOnly="True" SelectionMode="Extended" SelectionUnit="Cell">
<DataGrid.Columns>
<DataGridTextColumn Header="Item Id" x:Name="vrContractID" Binding="{Binding Path=ItemId, Mode=OneWay}" MinWidth="50" />
<DataGridTextColumn Header="Item #" Binding="{Binding Path=ItemNumber, Mode=OneWay}" MinWidth="50"/>
<DataGridCheckBoxColumn Header="Valid?" Binding="{Binding Path=IsValid, Mode=OneWay}" MinWidth="5"/>
<DataGridTextColumn Header="Error Code" Binding="{Binding Path=ErrorCode, Mode=OneWay}" MinWidth="50"/>
<DataGridTextColumn Header="Error Message" Binding="{Binding Path=ErrorMessage, Mode=OneWay}" Width="*"/>
</DataGrid.Columns>
</DataGrid>
I'm trying not to use XAML based binding like I have showed you above however, I'm having issues understanding how to accomplish this style of binding in the code behind file using something like:
this.Bind()
Or this:
this.OneWayBind()
I've had similar issues binding DataTemplates and MultiBinding and this makes me wonder if there is something I'm missing about the design pattern for ReactiveUI/MVVM.
Any help would be appreciated.
PS: If I must bind this using xaml binding - why wouldn't I just do all my binding in xaml? It sort of feels weird to have 2 places where binding can occur.
The solution with DataTemplates is to not set one and the rxui binding will automatically provide one and look for registered IViewFor<TViewModel> registered for the view model and show that view.
Multi binding you can use Observable.CombineLatest with multiple WhenAny operators and then use BindTo.
With data grid the story is you can programmatically generate the columns then use rxui binding on those. In the past I have used a builder pattern for it. The DataGrid out of the box isn't really easy to combine with rxui binding.
I’m using WPF MVVM DataGrid and one of the columns is the equivalent of DataGridComboBoxColumn, but made of DataGridTemplateColumn .
DataGrid itself is binded to one object, and ComboBox column is binded to the separate one.
The XAML code is:
<DataGrid Grid.Column="0" AutoGenerateColumns="False" CanUserAddRows="False" ItemsSource="{Binding ItemNamesSetting}">
<DataGrid.Columns>
<DataGridTextColumn Header="Item1" Binding="{Binding Path=OriginalItemName}" />
<DataGridTextColumn Header="Item2" Binding="{Binding Path=FinalItemName}" />
<DataGridTemplateColumn Header="Attribute">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding DataContext.AttributesBindingList, ElementName=ThirdStepTab}" DisplayMemberPath="PropName" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Item3" Binding="{Binding Path=Separatopr}" />
</DataGrid.Columns>
</DataGrid>
The question is how can I get the full row data? I’m planning to have one “Save” button that would send data to the database and I need to get data in text columns + data at ComboBox from different ource – row by row. Is there a way to do it?
Thank you.
You need to bind the SelectedItem property of DataGrid to your MVVM view Model. Also, the one of relevant property of view model should bind to Combobox SelectedValue
<DataGrid Grid.Column="0" AutoGenerateColumns="False" CanUserAddRows="False" ItemsSource="{Binding ItemNamesSetting}" SelectedItem="{Binding VMPropertyName}" >
<DataGrid.Columns >
<DataGridTextColumn Header="Item1" Binding="{Binding Path=OriginalItemName}" />
<DataGridTextColumn Header="Item2" Binding="{Binding Path=FinalItemName}" />
<DataGridTemplateColumn Header="Attribute">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding DataContext.AttributesBindingList, ElementName=ThirdStepTab}" DisplayMemberPath="PropName" SelectedValue="{Binding PropertyOfVM}" />
</DataTemplate> </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Item3" Binding="{Binding Path=Separatopr}" />
Im new to WPF and C# so please dont rip my head of if i should have done something stupid^^
Im trying to show some data from a SQLite Database file by using a DataGrid. I already installed the relevant package from the SQLite page that includes the VisualStudios designer components. I added the Databasefile as a datasource in Visual Studios which worked pretty good. If i open the Database with the datapreview function it shows my Data the way it should.
My Problem is that even tho i boundet the Datasource as shown on the MSDN page it still isnt showing any Entries, but it sucessfully created all Colums.
Heres my XAML Code:
<Page.Resources>
<local:WorkDataSet x:Key="WorkDataSet"/>
<CollectionViewSource x:Key="personalViewSource" Source="{Binding Personal, Source={StaticResource WorkDataSet}}"/>
<Grid DataContext="{StaticResource personalViewSource}">
<Label Content="Personal" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="20" FontSize="20" FontWeight="Bold"/>
<DataGrid x:Name="personalDataGrid" AutoGenerateColumns="False" EnableRowVirtualization="True" ItemsSource="{Binding}" Margin="10,100,10,10" RowDetailsVisibilityMode="Visible">
<DataGrid.Columns>
<DataGridTextColumn x:Name="iDColumn" Binding="{Binding ID}" Header="ID" Width="SizeToHeader"/>
<DataGridTextColumn x:Name="stationColumn" Binding="{Binding Station}" Header="Station" Width="SizeToHeader"/>
<DataGridTextColumn x:Name="nameColumn" Binding="{Binding Name}" Header="Name" Width="SizeToHeader"/>
<DataGridTextColumn x:Name="_ACD_IDColumn" Binding="{Binding ACD-ID}" Header="ACD-ID" Width="SizeToHeader"/>
<DataGridTemplateColumn x:Name="bild1Column" Header="Bild 1" Width="SizeToHeader">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding Bild1}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn x:Name="bild2Column" Header="Bild 2" Width="SizeToHeader">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding Bild2}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn x:Name="visitColumn" Header="Visit" Width="SizeToHeader">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<DatePicker SelectedDate="{Binding Visit, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
as far as is understood this it should not require any further C# code cause everything should be set automaticly by Visual Studios.
I know there are a view Questions like this arround here but non of these use SQLite in the way i do...
I have a WPF application with a datagrid. On load my ViewModel populates a list called HldChangeList. This list is bound to the data grid. The list contains approx. 200 items but at the moment the list shows 10 empty rows but no column headers. I've put a stop in my setter and can see the code is getting there. Not sure what else I am missing.
View Model
private List<HoldingPrePost> _hldChangeList;
public List<HoldingPrePost> HldChangeList
{
get
{
return _hldChangeList;
}
set
{
_hldChangeList = value;
OnPropertyChanged("HldChangeList");
}
}
XAML
<DataGrid x:Name="dataGridHoldings"
DataContext="{Binding HldChangeList}"
AutoGenerateColumns="False"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="Silver"
RowHeaderWidth="30"
ItemsSource="{Binding Path=HldChangeList, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource DataGridTemplate}"
ColumnHeaderStyle="{StaticResource DG_ColumnHeader}"
RowStyle="{StaticResource DG_Row}"
CellStyle="{StaticResource DG_Cell}"
RowHeaderStyle="{StaticResource DG_RowHeader}"
Margin="15,5,20,15" >
<DataGridTextColumn Header="ABC" Binding="{Binding ABC}" IsReadOnly="True"/>
<DataGridTextColumn Header="DEF" Binding="{Binding DEF}" IsReadOnly="True"/>
<DataGridTextColumn Header="GHI" Binding="{Binding GHI}" IsReadOnly="True"/>
</DataGrid>
You're setting both DataContext and ItemsSource to HldChangeList
<DataGrid
DataContext="{Binding HldChangeList}"
ItemsSource="{Binding Path=HldChangeList, UpdateSourceTrigger=PropertyChanged}"/>
WPF will search for HldChangeList items source property in current binding context which you also set to HldChangeList so in your case it will look for HldChangeList.HldChangeList property. If HldChangeList is already part of current binding context then you don't need to change DataContext otherwise you need to set it to something that contains HldChangeList property
EDIT
You forgot to enclose column definitions in DataGrid.Columns tag
<DataGrid x:Name="dataGridHoldings" ... ItemsSource="{Binding Path=HldChangeList}">
<DataGrid.Columns>
<DataGridTextColumn Header="ABC" Binding="{Binding ABC}" IsReadOnly="True"/>
<DataGridTextColumn Header="DEF" Binding="{Binding DEF}" IsReadOnly="True"/>
<DataGridTextColumn Header="GHI" Binding="{Binding GHI}" IsReadOnly="True"/>
</DataGrid.Columns>
</DataGrid>
As dkozl said,
you need to set ItemsSource of your DataGrid explicitly without setting its DataContext or implicitly by setting the DataContext
Implicit
<DataGrid ...
DataContext="{Binding HldChangeList}" ...
ItemsSource="{Binding}" ... />
Explicit
<DataGrid ...
ItemsSource="{Binding HldChangeList}" ... />