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.
Related
I have a Data Grid that is bound to a object of type MyStaff. Apart from other properties MyStaff contains a column named LookupID. Now, in my ViewModel I have a collection Named Lookups that have a description for each LookupID.
I have a Template column that has a Textblock in Cell Template and Combobox in CellEdit Template. How do I bind the Textblock so that it dsiplays the description from ComboBox based on LookupID.
I know it would be pretty simple if the datacontext for both the Textblock and ComboBox were simple but that is not the case.
I have tried this but this doesn't work. Any suggestions? Also would appreciate any information on how to best use different Data Context for different controls in Silverlight. For this I have added a static resource pointing to the ViewModel Class.
<sdk:DataGridTemplateColumn Header="Action Point"
Width="500"
CanUserReorder="False"
HeaderStyle="{StaticResource dthFull2}"
IsReadOnly="False">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock
Text="{Binding ElementName=LookupList,
Path=SelectedItem.Description}"
MinHeight="24"
VerticalAlignment="Top"
Padding="2"
TextTrimming="WordEllipsis"/>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
<sdk:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<my:AutoCompleteComboBox x:Name="LookupList"
FilterMode="Custom" Margin="2,0,0,0"
SelectedValue="{Binding LookupID, Mode=TwoWay}"
SelectedValuePath="LookupID"
ItemsSource="{Binding Path=AnalysisLookupList.Values,
Source={StaticResource ViewModel}}"/>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellEditingTemplate>
</sdk:DataGridTemplateColumn>
I have a multiselect combobox that works fine. Except for the text. I want it to always have the same text ("Commodity Filter") regardless of what the user has selected.
If I set iseditable to true and the text to CommodityFilter it looks fine until the user makes a selection, then it is garbage (displays object type name). How can I hard code some text there? (Actually ideally i would databind it so it can change depending on whether anything is selected, but that would be a bonus at this point)
<ComboBox IsEditable="True" Text ="Commodity Filter" ItemsSource="{Binding Path=ActiveCommodities}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsSelected}"
Width="20" />
<TextBlock Text="{Binding Commodity}"
Width="100" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
I ended up creating a custom object for populating the ComboBox (which had the IsSelected property and implemented INotifyPropertyChanged) because I was creating several comboboxes to control filtering. Once I did this is was trivial to override the tostring on the customobject and pass in the appropriate text. So the xaml did not change much.
I would have preferred to overlay with a text box but that seemed to be beyond my abilities to get a polished look in a reasonable time.
<ComboBox ItemsSource="{Binding Path=ActiveFuturesMonths}"
IsEditable="True"
IsReadOnly="True"
Text="Futures Month Filter" >
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsSelected}"
Width="20" />
<TextBlock Text="{Binding Text}"
Width="100" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Actually the crux is in setting -
IsEditable="True"
IsReadOnly="True"
Text="Futures Month Filter"
rather than creating custom object. thanks a lot it helped.
I have a ComboBox that shows text of various lengths. For texts that are not long there is not a problem. For the texts longer than the width of ComboBox I would like to trim the text and add "..." (an ellipsis) at the end to show them properly. The bottom line is that I don't want to change the width of the ComboBox. Does anyone know how to do this?
Use a custom ItemTemplate for your ComboBox, which makes use of a TextBlock with the TextTrimming property set to CharacterEllipsis.
Example:
<ComboBox ItemsSource="..." SelectedValuePath="...">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock
Text="{Binding ...}"
TextTrimming="CharacterEllipsis" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
The answer, as Ross said, is to implement a custom ItemTemplate. However, to make it work properly, you need to do the binding properly.
A note on this method: You cannot set both the DisplayMemberPath and the ItemTemplate, it must be one or the other.
So, for the general case where the display member is the item (such as for a string), you can use binding with no properties to bind to the DataContext of the template:
<ComboBox ItemsSource="..." SelectedValuePath="...">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding }" TextTrimming="CharacterEllipsis" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Or, you can put it in a style.
<Style TargetType="{x:Type ComboBox}">
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding }" TextTrimming="CharacterEllipsis" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
For the case where you want to bind to a specific property of the object, similar to how you would use the DisplayMemberPath property, replace the binding with the binding that you would use to a property on the object that you are binding. So, replace the fourth line in my first example with something like this:
<TextBlock Text="{Binding MyDisplayMemberProperty}" TextTrimming="CharacterEllipsis" />
The binding is in the context of a single item of the type bound to your ComboBox. To make this more explicit, you can do the following:
<DataTemplate DataType="{x:Type namespace:MyItemType}">
<!-- My DataTemplate stuff here -->
</DataTemplate>
This will give you hints for the properties on the object while you are writing code inside the DataTemplate.
You can use TextTrimming CharacterEllipsis or WordEllipsis for the textblocks in your combobox.
Also works with a more complex DataTemplate; however, I had to resort to a DockPanel instead of the standard WrapPanel.
<ComboBox>
<ComboBox.ItemTemplate>
<DataTemplate>
<DockPanel>
<AccessText DockPanel.Dock="Left" Text="{Binding Icon}"/>
<TextBlock Text="{Binding Name}" TextTrimming="CharacterEllipsis" />
</DockPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
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 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>