I have a DataGrid where there are Date0, Date1, and Date2 columns. I can change the columns with a ComboBox.
I started to use DataTemplate. The CellTemplate uses Date0InParameterEditingTemplate where I bind Date0 which is not simple DateTime but a class. Then this class is bound to DateEditingTemplate. I would like to use DateEditingTemplate later with Date1 and Date2 as well.
The data goes well to one direction, so the ComboBox displays the proper date. When I select a new value in the ComboBox then the SelectedItem changes. But the content of ContentControl remains unchanged.
<DataGridTemplateColumn Header="{x:Static r:Resource.Date0}"
CellTemplate="{StaticResource Date0InParameterEditingTemplate}"/>
<DataTemplate x:Key="DateEditingTemplate">
<ComboBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type DataGrid}}, Path=DataContext.ValidDateObjects}"
SelectedItem="{Binding Path=., Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
DisplayMemberPath="Date" Style="{StaticResource ComboBoxError}" IsEditable="False"
ItemStringFormat="{StaticResource DateFormatHU}" />
</DataTemplate>
<!--<DataTemplate x:Key="DateEditingTemplate">
<TextBlock Text="{Binding Date}"/>
</DataTemplate>-->
<DataTemplate x:Key="Date0InParameterEditingTemplate">
<ContentControl Content="{Binding Date0, ValidatesOnDataErrors=True, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ContentTemplate="{StaticResource DateEditingTemplate}"/>
</DataTemplate>
Related
In a DataGrid I display data about financial transactions. One column is the Account with the xaml below. The CellEditingTemplate display the ComboBox with the accounts. The CellTemplate is tricky. I want to display the Account as a TextBlock. Previously I bound "Account.Name" but validating a nested property is not easy if Account is null (e.g. in a new row). So I decided to use ComboBox but with a ControlTemplate. Displaying values and validation works. The problem is that for click the CellEditingTemplate is not activated.
<DataGridTemplateColumn Header="{x:Static r:Resource.AccountName}">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type DataGrid}}, Path=DataContext.AccountObjects}"
SelectedItem="{Binding Account, ValidatesOnDataErrors=True}"
DisplayMemberPath="Name">
<ComboBox.Template>
<ControlTemplate TargetType="{x:Type ComboBox}">
<TextBlock Text="{TemplateBinding Text}"/>
</ControlTemplate>
</ComboBox.Template>
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type DataGrid}}, Path=DataContext.AccountObjects}"
SelectedItem="{Binding Account, ValidatesOnDataErrors=True}"
DisplayMemberPath="Name"/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
In a DataGrid one of the columns is Account. I want to select AccountId but the ComboBox should display AccountNames. So I created the xaml below. It works as required but it has a drawback. If I change the account and go to another cell in the same row then AccountName is not updated yet. (If I leave the row then AccountName is calculated and updated based on the new AccountId.)
If I use only CellTemplate with the ComboBox then I evaded the problem but I do not like this solution because it is not nice to show the ComboBoxes when they are not needed. I could try to update AccountName when I leave the cell but my db view would do that and at this point there could be errors in the current row. So I would like to show the selected AccountName as a TextBlock in CellTemplate based on the AccountId. (I tried to put the ComboBox into the TextBlock but then the TextBlock does not just show the selected AccountName but the ComboBox itself.)
<DataGridTemplateColumn Header="{x:Static r:Resource.AccountName}">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding AccountName, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource TextBlockError}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type DataGrid}}, Path=DataContext.AccountObjects}"
SelectedValue="{Binding AccountId, ValidatesOnDataErrors=True, UpdateSourceTrigger=LostFocus}"
SelectedValuePath="Id"
DisplayMemberPath="Name"
Style="{StaticResource ComboBoxError}" IsEditable="True"/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
You should bind to a Account property of your data object and implement the INotifyPropertyChanged interface. You may also want to set the UpdateSourceTrigger property to PropertyChanged:
<ComboBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type DataGrid}}, Path=DataContext.AccountObjects}"
SelectedItem="{Binding Account, UpdateSourceTrigger=PropertyChanged}"
DisplayMemberPath="Name"
Style="{StaticResource ComboBoxError}" IsEditable="True"/>
The answer of #mm8 helped me a lot.
Until now there was only int AccountId in my model file.
I introduced Account Account navigation property which created foreign key in the db.
(I am using Enitity Framework.)
When the db is updated Account is not changed only AccountId.
(Otherwise there are problems with the db, EF think it should insert a new Account instead using the existing one.)
Now the setter of the Account property also changes the AccountId.
Account implements IEquatable
otherwise the initial value of the ComboBox is not displayed
Finally the xaml (SelectedItem="{Binding Account}" and Text="{Binding Account.Name}" is used)
<DataGridTemplateColumn Header="{x:Static r:Resource.AccountName}">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Account.Name, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource TextBlockError}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type DataGrid}}, Path=DataContext.AccountObjects}"
SelectedItem="{Binding Account, ValidatesOnDataErrors=True, UpdateSourceTrigger=LostFocus}"
DisplayMemberPath="Name"
Style="{StaticResource ComboBoxError}" IsEditable="True"/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="ToolTip">
<Setter.Value>
<TextBlock Text ="{Binding Account.Name}" TextWrapping="Wrap" MaxWidth="300"/>
</Setter.Value>
</Setter>
</Style>
</DataGridTemplateColumn.CellStyle>
</DataGridTemplateColumn>
I have Datagrid with two TemplateColumn.
First column is a Combobox and Second column with Extended IntergerUpDown control
I need to Enable/Disable the IntegerUpDown control based on the Combox box SelectedItem value.
Please help me how to accomplish this. Sample xaml below.
<Grid><DataGrid ItemsSource="{Binding List1}" Name="x1">
<DataGrid.Columns>
<DataGridTemplateColumn Header="ColorTemplate">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding DataContext.List2, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGrid}}}"
DisplayMemberPath="Name" SelectedValue="{Binding ColourId}" SelectedValuePath="Id" Tag="{Binding Id}"
HorizontalAlignment="Stretch" x:Name="discussTemplate" VerticalAlignment="Stretch"
/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="UPDown" Width="Auto">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<extToolkit:IntegerUpDown AllowSpin="True" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="Auto" Minimum="0"
x:Name="updown"
IsEnabled="????" >
</extToolkit:IntegerUpDown>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
This can be easily done with a DataTrigger on your ViewModel ColourId property.
As your SelectedValue property on the ComboBox is already binded, you can have a DataTrigger on your extToolkit:IntegerUpDown control that will set IsEnabled to True/False based on ColourId value on your ViewModel.
I have a WPF form with a DataGrid. This DG contains a DataGridTemplateColumn that contains a ComboBox. When I click on the new row of the DG and selected a value from the Combobox and then tab to the next column, the selected value does not stay visible in the combobox column.
However, when I tab back, the correct value shows in the combobox.
How do I keep the selected value showing in the combobox column when I tab off the column?
Here is my comboxbox column xaml:
<DataGridTemplateColumn Header="Type" Width="160">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding LocationType.Description, Mode=TwoWay}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<ComboBox Name="cboAddrtype"
ItemTemplate="{StaticResource dtAddrType}" IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}, AncestorLevel=1}, Path=DataContext.LocationTypesObject, Mode=OneTime}"
SelectedItem="{Binding Path=SelectedLocationType, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
SelectedValue="{Binding Path=LocationTypeKey, Mode=TwoWay}"
SelectedValuePath="InternalKey"
Width="100" />
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
In CellTemplate you're binding LocationType.Description and in CellEditingTemplate you're binding SelectedLocationType and LocationTypeKey. I'm not sure that your binding from ComboBox won't somehow affect LocationType.Description.
Furthermore, SelectedLocationType and LocationTypeKey are not in the context of DataTemplate. You should add a Source binding property to get your ViewModel.
First the code:
<ListView ItemsSource="{Binding DataTransferModel.Output}" Background="Transparent" Margin="0" VerticalContentAlignment="Top" AlternationCount="2" Name="lvOutput" ScrollViewer.VerticalScrollBarVisibility="Auto" Grid.Row="2">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="0,1">
<UserControls:OutputTextBox Text="{Binding Data, Mode=OneWay}"
IsReadOnly="True"
Grid.Row="2"
TextWrapping="WrapWithOverflow"
SelectedValue="{Binding Path=DataContext.SelectedOutput,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged,
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Grid}}
}"
/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
And the problem is that the property Data on the OutputTextBox control comes from the list, but the property SelectedOutput should come from the main DataContext the ViewModel. And the property SelectedOutput should be the same for every entry in the list. But currently it dosn't work. :(
does your listview is enclosed in tags and if yes does the grid has the DataContext from the ViewModel? if yes it should work.
do you see any binding errors in your output window? maybe you should try using Snoop to see your real binding of SelectedValue.
EDIT: Please try a Type other then Grid, maybe ListView if it has the ViewModel DataContext.
<UserControls:OutputTextBox Text="{Binding Data, Mode=OneWay}"
IsReadOnly="True"
Grid.Row="2"
TextWrapping="WrapWithOverflow"
SelectedValue="{Binding Path=DataContext.SelectedOutput,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged,
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}
}"
/>