I have this RadComboBox placed inside a RadGridViewDataColumn:
<tk:RadGridView
Name="grdPeople"
ItemsSource="{Binding People}"
SelectedItem="{Binding SelectedPerson, Mode=TwoWay}">
<tk:GridViewDataColumn
DataMemberBinding="{Binding PeopleDetails}"
UniqueName="PeopleDetails"
Header="People">
<tk:GridViewDataColumn.CellTemplate>
<TextBlock
Text="{Binding Title}"/>
</tk:GridViewDataColumn.CellTemplate>
<tk:GridViewDataColumn.CellEditTemplate>
<tk:RadComboBox
DisplayMemberPath="TitleValue"
SelectedItem="{Binding Path=People.Title, Mode=TwoWay}"
ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type tk:RadGridView}}, Path=DataContext.Titles}"/>
</tk:GridViewDataColumn.CellEditTemplate>
</tk:GridViewDataColumn>
</tk:RadGridView>
I know that the problem comes with mixing of the RadGridView and the window data context objects, but not sure, why title doesn't get saved in the DB?
On the contrary, if I replace the RadComboBox with ordinary TextBox:
<TextBox
Width="50"
Text="{Binding Title}"
TextAlignment="Left"/>
Typing the value in a text box works just fine, saving the title in the DB.
I am guessing its, something with mixing the various components in the cell edit template of RadGridView?
Just change the Path of SelectedItem binding from 'People.Title' to 'Title'
<tk:RadComboBox
DisplayMemberPath="TitleValue"
SelectedItem="{Binding Path=Title, Mode=TwoWay}"
ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type tk:RadGridView}}, Path=DataContext.Titles}"/>
Related
My problem is that I can't seem to time the selection changed event from the ComboBox edit, to the TextBlock update. Everything displays property but when I'm getting the Grade in the SelectionChanged event in the code behind, it's not updated with the actual value. To get the actual value I have to change the selection on the ComboBox then click off the line of the datagrid I'm editing. Then when I choose a new grade it is updated to show what the last grade was selected. So even though it seems it should all be connected, the row does not actually update until I click off it, as opposed to when I make a different ComboBox selection. So is there any way to change the way a datagrid updates the data to keep in sync with the ComboBox? Any help is appreciated. Thanks.
<DataGridTemplateColumn Header="Grade" CellStyle="{StaticResource StarNumberCellStyle}">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Grade}" Margin="3,1,3,1">
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding DataContext.Grades, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}"
SelectedItem="{Binding Grade,Mode=TwoWay, NotifyOnTargetUpdated=True}" Tag="{Binding}" ComboBox.IsTextSearchEnabled = "True">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding DataContext.GradeSelectCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}"
CommandParameter ="{Binding}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
See my answer about DataGridTemplateColumn caveats here: DataGrid and Observable Collection in WPF
In short, this should work for you (UpdateSourceTrigger=PropertyChanged):
<ComboBox ...
SelectedItem="{Binding Grade, UpdateSourceTrigger=PropertyChanged,
Mode=TwoWay, NotifyOnTargetUpdated=True}"
... >
I have the following xaml code:
<ListBox Foreground="{Binding MyColor, Converter={local:ColorConverter}}" ItemsSource="{Binding LogCollection, Mode=TwoWay}" Grid.Row="1">
</ListBox>
This changes the foreground color for the entire listbox, so I modified the code in this way:
<ListBox ItemsSource="{Binding LogCollection, Mode=TwoWay}" Grid.Row="1">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Foreground="{Binding MyColor, Converter={local:ColorConverter}}" Text="{Binding}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
In this way I wanted to set the foreground for an item instead for the entire listbox, but it is not working. How do I find the right datacontext ? MyColor is a property on my MainViewModel.
LATER EDIT WITH THE SOLUTION
Jens's answer was the one that showed me where I was wrong. Instead of storing simple message log strings in the ObservableCollection, I created a new class (LogItems) which contains a Message and a Color members. Now the LogCollection is typeof LogItems instead of strings.
I populate the listbox with the following code in my viewmodel:
LogItems logitem = new LogItems(myMessage, myColor);
LogCollection.Insert(0, logitem);
And the view has the following form. Also it doesn't require anymore to use RelativeSource, because the datacontext is the same.
<ListBox ItemsSource="{Binding LogCollection, Mode=TwoWay}" Grid.Row="1">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Foreground="{Binding Path=Color, Converter={local:ColorConverter}}" Text="{Binding Path=Message}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Thank you all for your answers which lead me to this solution.
The DataContext of generated container in a listbox is automatically set to the corresponding item, therefore your Binding does not find the Property MyColor. You need to use a RelativeSource binding to bind to the DataContext of the containing list:
<TextBlock Foreground="{Binding DataContext.MyColor,
RelativeSource={RelativeSource
Mode=FindAncestor,
AncestorType={x:Type ListBox}},
Converter={local:ColorConverter}}"
Text="{Binding}"/>
I am working with DataGrid. One column displays text, but the data behind this contains only an id. This id must somehow be converted to a string.
I need something like a combobox with the properties ItemsSource, DisplayMemberPath, SelectedValue and SelectedValuePath. But instead of a button displayed, there must be only a text. Is there some control for that?
That works (would like to exchange combobox with something that looks like textbox):
<DataGridTemplateColumn Header="Leistungsart" MinWidth="100">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Source={StaticResource ResourceKey=viewModel}, Path=Leistungsarten}"
DisplayMemberPath="Bezeichnung"
SelectedValue="{Binding Path=BDELeistungsartID, Mode=OneWay, Converter={StaticResource ResourceKey=NullableInt2IntConverter}}"
SelectedValuePath="BDELeistungsartID"
IsEnabled="false"
IsEditable="False"
Height="35">
</ComboBox>
</DataTemplate>
Thanks a lot for your aswer. Yes, that with Template property worked for me:
<ComboBox ItemsSource="{Binding Source={StaticResource ResourceKey=viewModel}, Path=Leistungsarten}"
DisplayMemberPath="Bezeichnung"
SelectedValue="{Binding Path=BDELeistungsartID, Mode=OneWay, Converter={StaticResource ResourceKey=NullableInt2IntConverter}}"
SelectedValuePath="BDELeistungsartID">
<ComboBox.Template>
<ControlTemplate>
<Label Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=SelectedItem.Bezeichnung}"
Margin="0,0,0,0" Padding="0,0,0,0"/>
</ControlTemplate>
</ComboBox.Template>
</ComboBox>
You could use a ComboBox, but overwrite the Template property to show just a Label. You'll have to recreate the Click events too.
Easiest way would be to use a tool like Snoop or Blend and see what the default ComboBox template looks like, and modify that to what you want.
In the XAML below the ToolTip correctly binds to RelativeSource Self. However, I can't for the life of me work out how to get the TextBlock in the commented block to refer to SelectedItem.Description
<Controls:RadComboBoxWithCommand x:Name="cmbPacking"
Grid.Row="2"
Grid.Column="5"
ItemsSource="{Binding PackingComboSource}"
DisplayMemberPath="DisplayMember"
SelectedValuePath="SelectedValue"
SelectedValue="{Binding ElementName=dataGrid1, Path=SelectedItem.PackingID}"
ToolTip="{Binding RelativeSource={RelativeSource Self}, Path=SelectedItem.Description}"
IsSynchronizedWithCurrentItem="True"
Style="{StaticResource comboBox}">
<!-- <Controls:RadComboBoxWithCommand.ToolTip>-->
<!-- <TextBlock Text="{Binding RelativeSource={RelativeSource Self}, Path=SelectedItem.Description}" TextWrapping="Wrap" Width="50"/>-->
<!-- </Controls:RadComboBoxWithCommand.ToolTip>-->
</Controls:RadComboBoxWithCommand>
I would appreciate any suggestions
Thanks - Jeremy
It seems that since ToolTip does not have a parent, you need to bind to the placement target as below:
<Controls:RadComboBoxWithCommand Grid.Row="2"
Grid.Column="5"
ItemsSource="{Binding PackingComboSource}"
DisplayMemberPath="DisplayMember"
SelectedValuePath="SelectedValue"
SelectedValue="{Binding ElementName=dataGrid1, Path=SelectedItem.PackingID}"
IsSynchronizedWithCurrentItem="True"
Style="{StaticResource comboBox}">
<Controls:RadComboBoxWithCommand.ToolTip>
<ToolTip DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget}">
<TextBlock Text="{Binding SelectedItem.Description}"
TextWrapping="Wrap"
Width="100" />
</ToolTip>
</Controls:RadComboBoxWithCommand.ToolTip>
</Controls:RadComboBoxWithCommand>
Hope this is useful for someone
Jeremy
A relative source of self means the current object, which would be the TextBox itself in this particular case. You want a relative source of find ancestor with an ancestor type of RadComboBoxWithCommand. Alternatively, and perhaps a little simpler, is to give the combo box a name and use ElementName in your binding instead of a relative source:
<ComboBox x:Name="cb" ...>
<ComboBox.ToolTip>
<TextBlock Text="{Binding SelectedItem.Description, ElementName=cb}" .../>
I have a Datagrid with a combo box bound column that works great as follows:
<tk:DataGridComboBoxColumn SelectedValueBinding="{Binding DefaultLocationID}"
SelectedValuePath="LocationID"
DisplayMemberPath="LocationName"
Header="Default Location"
ItemsSource="{Binding Source={StaticResource CustomerLocations}}">
</tk:DataGridComboBoxColumn>
Ultimately I want to customize the dropdown to show 'ID' and 'Name' together so a TemplateColumn seems to be the way to go. Starting small, I can't get the following simple example to work which should replace the standard DataGridComboBoxColumn. The dropdown appears fine, but when I 'select' a dropdown item, it does not accept and goes back to the previous value. I've tried variations on 'Mode=TwoWay' but no luck. Do I need a 'CellEditingTemplate' ?
DefaultLocationID is the foreign-key field being edited, while 'LocationID' is a column in 'CustomerLocations'.
<tk:DataGridTemplateColumn Header="Default Location">
<tk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox VerticalAlignment="Top"
SelectedItem="{Binding LocationID, Mode=TwoWay}"
SelectedValue="{Binding DefaultLocationID, Mode=TwoWay}"
ItemsSource="{Binding Source={StaticResource CustomerLocations}}"
SelectedValuePath="LocationID"
DisplayMemberPath="LocationName" >
</ComboBox>
</DataTemplate>
</tk:DataGridTemplateColumn.CellTemplate>
Thanks!!
Can you post the relevant parts of your CustomerLocations resource? Can you also post the type of class that your grid is binding to?
Try removing the SelectedValuePath, DisplayMemberPath and SelectedValue from the ComboBox.
If you want to display multiple pieces of data in your combobox see the below XAML
<ComboBox ...>
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding LocationId}"} />
<TextBlock Text=" - "/>
<TextBlock Text="{Binding LocationName}"} />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>