I have done every thing I can think of, but the textbox just does not display the values.
Where is my mistake?
<dxg:GridColumn FieldName="secUserName" Header="TRAIL">
<dxg:GridColumn.DisplayTemplate>
<ControlTemplate>
<StackPanel>
<TextBox Text="{Binding Path=Data.secUserName, Mode=TwoWay}" ></TextBox>
</StackPanel>
</ControlTemplate>
</dxg:GridColumn.DisplayTemplate>
and in vb
'<!-- load the datagrid -->
Module1._Context.Load(Module1._Context.GetGESECsQuery())
GridControl1.AutoPopulateColumns = False
GridControl1.DataSource = Module1._Context.GESECs
I suggest that you use our TextEdit instead of the standard TextBox:
<dxg:GridColumn.DisplayTemplate>
<ControlTemplate>
<StackPanel>
<TextEdit EditValue="{Binding Path=DataContext.secUserName}"></TextEdit>
</StackPanel>
</ControlTemplate>
</dxg:GridColumn.DisplayTemplate>
If this does not help, please remove the template and make certain that the grid has a column bound to the secUserName field and it shows data in runtime.
Related
I am trying to customize a DataGrid. I want to insert some content above the column headers. I am trying to use the ControlTemplate to do this. I have my XAML code below. My problem is that the <ContentPresenter /> is not outputting anything. When I load the page, the after TextBlock appears directly below the before TextBlock with nothing in between. I want to display the column headers in that space.
<DataGrid ItemsSource="{Binding List}" AutoGenerateColumns="True">
<DataGrid.Template>
<ControlTemplate>
<StackPanel Orientation="Vertical">
<TextBlock>before</TextBlock>
<ContentPresenter /> <!-- outputs nothing -->
<TextBlock>after</TextBlock>
<ItemsPresenter />
</StackPanel>
</ControlTemplate>
</DataGrid.Template>
</DataGrid>
How do I display the column headers between the before TextBlock and the after TextBlock? My List object is simply a BindingList of some generic class that has a couple of public properties.
I found the answer. I should use <DataGridColumnHeadersPresenter /> instead of <ContentPresenter />. So my code that works looks like:
<DataGrid ItemsSource="{Binding List}" AutoGenerateColumns="True">
<DataGrid.Template>
<ControlTemplate>
<StackPanel Orientation="Vertical">
<TextBlock>before</TextBlock>
<DataGridColumnHeadersPresenter />
<TextBlock>after</TextBlock>
<ItemsPresenter />
</StackPanel>
</ControlTemplate>
</DataGrid.Template>
</DataGrid>
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>
Ok, this is an embarassingly simple-looking problem, but is driving me crazy. I'm learning about DataTemplating and am trying to apply a very VERY simple ItemTemplate to a ListBox.
However, when I run my app, the template is completely ignored and I just get the standard-looking listbox, whereas in fact I'd expect to see a list of checkboxes with 'Test' along side.
I've tried this several times and always the same result. I've checked several resource on Google and all have the same kind of syntax for defining and ItemTemplate on a ListBox, so I really cannot see where I'm going wrong.
Code...
<Grid x:Name="LayoutRoot">
<ListBox x:Name="TestList"
SelectionMode="Multiple">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<CheckBox Content="Check this checkbox!"/>
<TextBlock>Test</TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.Items>
<ListBoxItem>Bob</ListBoxItem>
<ListBoxItem>Jim</ListBoxItem>
<ListBoxItem>Dave</ListBoxItem>
<ListBoxItem>Larry</ListBoxItem>
<ListBoxItem>Tom</ListBoxItem>
</ListBox.Items>
</ListBox>
</Grid>
Any help greatly appreciated. Sorry for such a dumb-seeming question, but I've really fallen at the first hurdle here :(
AT
ItemTemplate wont work when you put ListBoxItem directly as items. General concept is you databind a CRL collection to the ListBox.ItemsSource and then specify the ItemTemplate. Check the below code.
<Grid x:Name="LayoutRoot">
<ListBox x:Name="TestList" SelectionMode="Multiple">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<CheckBox Content="Check this checkbox!"/>
<TextBlock Text="{Binding}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.Items>
<sys:String>Bob</sys:String>
<sys:String>Jim</sys:String>
<sys:String>Dave</sys:String>
<sys:String>Larry</sys:String>
<sys:String>Tom</sys:String>
</ListBox.Items>
</ListBox>
</Grid>
where sys is xmlns:sys="clr-namespace:System;assembly=mscorlib"
In this way, there are 5 ListBoxItems getting generated in the background and added to the ListBox.
You can use ItemContainerStyle instead of ItemTemplate if you want to add ListBoxItems directly to the ListBox.
Doing so, however, is only recommended when you need unique characteristics on a per item level.
If you are planning on all the items looking the same or making a dynamic list using ItemsSource, I would recommend you add strings (or another custom object) to your list and use ItemTemplate to display your items. (see Jobi Joy's answer)
Here's an example using ItemContainerStyle:
<ListBox
x:Name="TestList"
SelectionMode="Multiple">
<ListBox.ItemContainerStyle>
<Style
TargetType="ListBoxItem">
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate
TargetType="ListBoxItem">
<StackPanel>
<CheckBox
Content="Check this checkbox!" />
<TextBlock
Text="{TemplateBinding Content}" />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.Items>
<ListBoxItem>Bob</ListBoxItem>
<ListBoxItem>Jim</ListBoxItem>
<ListBoxItem>Dave</ListBoxItem>
<ListBoxItem>Larry</ListBoxItem>
<ListBoxItem>Tom</ListBoxItem>
</ListBox.Items>
</ListBox>
For some reason DataTemplate can still be ignored if the ListBox is populated using ItemsSource e.g:
<ListBox Name="Test" x:FieldModifier="public" ItemsSource="{Binding UpdateSourceTrigger=PropertyChanged}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Note that this is bound to an ObservableCollection containing objects (TextAdapter : INotifyPropertyChanged) with one property: string Text {...}
The goal:
I'm trying to achieve something like this in WPF:
(source: wordpress.org)
An initial solution:
At the moment, I'm trying to use an ItemsControl with an ItemTemplate composed of an Expander.
I want a consistent look for the Header portion of the Expander, but I want the Content portion of the Expander to be completely flexible. So, it's basically a set of "portlets" stacked vertically, where each portlet has a consistent title bar but different content.
The code so far:
This is what I have at the moment:
<ItemsControl
Grid.Row="2"
Grid.Column="2">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Expander>
<Expander.HeaderTemplate>
<DataTemplate>
<StackPanel
Orientation="Horizontal">
<TextBlock
FontSize="14"
FontWeight="Bold"
Text="Title_Of_Expander_Goes_Here" />
<TextBlock
Margin="10,0,0,0"
FontWeight="Bold"
FontSize="18"
Text="*" />
</StackPanel>
</DataTemplate>
</Expander.HeaderTemplate>
<Expander.Template>
<ControlTemplate
TargetType="Expander">
<Border
BorderThickness="1">
<ContentPresenter />
</Border>
</ControlTemplate>
</Expander.Template>
</Expander>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.Items>
<StackPanel>
<TextBlock
FontSize="14"
FontWeight="Bold"
Text="Users:" />
<wt:DataGrid
Margin="0,1,0,0"
AutoGenerateColumns="False"
CanUserAddRows="True"
CanUserDeleteRows="True"
ItemsSource="{Binding Source={StaticResource Main_SystemUsers}, XPath=//Users/*}">
<wt:DataGrid.Columns>
<wt:DataGridTextColumn
Header="User Name"
Binding="{Binding XPath=#UserName}" />
<wt:DataGridComboBoxColumn
Header="Role"
ItemsSource="{Binding Source={StaticResource Main_UserRoles}, XPath=//Roles/*}"
SelectedValueBinding="{Binding XPath=#Role}" />
</wt:DataGrid.Columns>
</wt:DataGrid>
<StackPanel
Margin="0,10,0,0"
Orientation="Horizontal">
<Button
Content="Add New User..." />
<Button
Margin="10,0,0,0"
Content="Delete User..." />
</StackPanel>
</StackPanel>
</ItemsControl.Items>
</ItemsControl>
Discussion:
The only thing that shows up when I run this is the DataGrid of users and the buttons ("Add New User" and "Delete User") below it. There is no Expander or title bar. Also, even if I did see one, I'm not sure how to set up a Binding for the title that appears on the title bar. I know how to do bindings if I use ItemsSource, but I wanted to set my items declaratively.
The question:
How should I go about this? I'm looking for either a fix for what I have now or a clean-sheet solution.
Edit:
What I ended up doing was replacing the ItemsControl with a StackPanel and just writing a style for my expanders. This proved to be much simpler, and there really was no benefit to the ItemsControl since I needed to declare custom content for each item anyway. The one issue remaining was how to achieve a custom title for each expander. That's where #Thomas Levesque's suggestion to use TemplateBinding came in. All I had to do was replace Text="Title_Of_Expander_Goes_Here" in my header's template (see code above) with Text="{TemplateBinding Content}".
You're not seeing the Expander because you redefined its template. This one should work better :
...
<Expander.Template>
<ControlTemplate
TargetType="Expander">
<Border
BorderThickness="1">
<Expander Content="{TemplateBinding Content}" Header="{TemplateBinding Header}"/>
</Border>
</ControlTemplate>
</Expander.Template>
...
Personally I think a TreeView control would give you a much better base to work from, especially if you're using Expression Blend as a basis to create new/blank Templates from for items. Seeing the default Templates is extremely enlightening and gives you much more fine-grained control and better understanding and insight into how things work by default. Then you can go to town on them. It also looks like you're working with Hierchical Data and TreeViews inherently lend themselves well to working with such data.
I have a WPF listbox which displays messages. It contains an avatar on the left side and the username and message stacked vertically to the right of the avatar. The layout is fine until the message text should word wrap, but instead I get a horizontal scroll bar on the listbox.
I've Googled and found solutions to similar issues, but none of them worked.
<ListBox HorizontalContentAlignment="Stretch" ItemsSource="{Binding Path=FriendsTimeline}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Border BorderBrush="DarkBlue" BorderThickness="3" CornerRadius="2" Margin="3" >
<Image Height="32" Width="32" Source="{Binding Path=User.ProfileImageUrl}"/>
</Border>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Path=User.UserName}"/>
<TextBlock Text="{Binding Path=Text}" TextWrapping="WrapWithOverflow"/> <!-- This is the textblock I'm having issues with. -->
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Contents of the TextBlock can be wrapped using property TextWrapping.
Instead of StackPanel, use DockPanel/Grid.
One more thing - set ScrollViewer.HorizontalScrollBarVisibility property to Disabled value for the ListBox.
Updated Hidden to Disabled based on comment from Matt. Thanks Matt.
The problem might not be located in the ListBox. The TextBlock won't wrap, if one of the parent controls provides enough space, so that it hasn't the need to wrap. This might be caused by a ScrollViewer control.
If you want to prevent TextBlock to grow, and you want it to just fit in the size of the listbox, you should set the width of it explicitly.
In order to change it dynamically, it means not a fix value, but you need to bind it to its proper parent element in the visual tree. You can have something like this:
<ListBox ItemsSource="{Binding MyItems}" Name="MyListBox">
<ListBox.Resources>
<Style TargetType="ListBoxItem">
<Setter Property="Width"
Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ScrollContentPresenter}, Path=ActualWidth}" />
</Style>
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Title}" TextWrapping="Wrap" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
If it does not work, try to find the proper elements (which has to be binded to what) with the Live Visual Tree in Visual Studio.