ListView style to add ellipsis (...) to all truncated text - wpf

I want to create a style for my ListViews in my WPF app, which makes them appear more like the Windows Explorer ListView. The thing I am stuck on is the ellipsis (...) that appears in the Grid/Details view when a column is too narrow to fix the text.
I know I can override the cell template of each column, and explicitly set the TextTrimming mode to get ellipsis on a per-column basis. However, I want a style that I can apply to any ListView to get the same behavior.
I want to be able to define the listview like this:
<ListView ItemsSource="{Binding Library}" Style="{StaticResource ExplorerListStyle}">
<ListView.View>
<GridView>
<GridViewColumn Width="90" Header="Title" DisplayMemberBinding="{Binding Title}" />
<GridViewColumn Width="60" Header="Author" DisplayMemberBinding="{Binding Author}" />
</GridView>
</ListView.View>
</ListView>
I also want to be able to override the cell template for some columns, e.g. to set the text color, ideally while still inheriting the TextTrimming mode for the text in the template.
The only way I have managed to achieve this so far is to explicitly override the TextBlock style inside the ListView:
<ListView ItemsSource="{Binding Library}">
<ListView.Resources>
<Style TargetType="TextBlock">
<Setter Property="TextTrimming" Value="CharacterEllipsis" />
</Style>
</ListView.Resources>
<ListView.View>
<GridView>
<GridViewColumn Width="90" Header="Title" DisplayMemberBinding="{Binding Title}" />
<GridViewColumn Width="60" Header="Author" DisplayMemberBinding="{Binding Author}" />
</GridView>
</ListView.View>
</ListView>
However, this seems a bit heavy handed, and it's not possible, as far as I can tell, to set this in a style.
So, I'm looking for another way to set the TextTrimming mode for a GridViewColumns header and cells, that can be set in a style, and doesn't require explicit CellTemplates.
Thanks,
Mark

Related

Binding GrivdViewColumn's Width Property in XAML or in Code?

I would like to bind GrivdViewColumn's Width Property with my ViewModel. Lets say an instance of ViewModel is the Datacontext of the Window. ViewModel has got Properties called IdWidth, LastNameWidth, FirstNameWidth. And that Window contains the following given ListVeiw in a stackPanel. Everything is fine but somehow the Width Property of GridViewColumn is not bound. Please post the code after making sure that it works.
<ListView Name="PatientListView"
ItemsSource="{Binding Patients}"
SelectionMode="Single">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="Patient-Id"
Width="{Binding IdWidth, Mode=TwoWay}"
DisplayMemberBinding="{Binding PatientId}"/>
<GridViewColumn Header="Last Name"
Width="{Binding LastNameWidth, Mode=TwoWay}"
DisplayMemberBinding="{Binding LastName}"/>
<GridViewColumn Header="Last Name"
Width="{Binding FirstNameWidth, Mode=TwoWay}"
DisplayMemberBinding="{Binding FirstName}" />
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
The accepted answer is wrong as outlined in my comment, looking at your paths you seem to expect the DataContext to be the item, which cannot work (there are multiple items to begin with, which should be chosen?).
The DataContext of the columns is the DataContext of the ListView.
This example will result in a column with the Header Lorem Ipsum:
<ListView>
<ListView.DataContext>
<Label Content="Lorem Ipsum"/>
</ListView.DataContext>
<ListView.View>
<GridView>
<GridViewColumn Header="{Binding Content}"/>
</GridView>
</ListView.View>
</ListView>
Also you might be interested in this article on debugging databindings.
Edit: FrameworkElement is not required for DataBinding, sorry for this incorrect interpretation of the citation from MSDN below.
See comments and #H.B. 's answer
GridViewColumn does not inherit from FrameworkElement, which is required for databinding.
see MSDN:
Support for data binding and dynamic resource references: [...], but the ability to resolve a member value that is stored as an Expression (the programming construct that underlies both data binding and dynamic resources) is implemented by FrameworkElement

How to show properties of a list in a list in a listview?

I am implementing an application in wpf , MVVM pattern.
I want to implement a listview with objects. These objects contains a list. On default this list contains only 1 object. But in the listview, I want to show that certain object. So the properties of the object in the list. This is my first problem.
But I also have to be able to have more objects in this list. My second problem is that i don't really know how to realise this? And i also have to show the properties of these objects in the listview.
Maybe a treeview? but i don't get how that i got to begin on this..
Someone with some ideas?
You can arbitrarily nest DataTemplates, e.g.
<ListView ItemsSource="{Binding Data}">
<ListView.View>
<GridView>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}"/>
<!-- Internal Manchines list gets its own ListView -->
<GridViewColumn Header="Machines">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ListView ItemsSource="{Binding Machines}">
<ListView.View>
<GridView>
<GridViewColumn Header="Model" DisplayMemberBinding="{Binding Model}"/>
<GridViewColumn Header="Manufacturer" DisplayMemberBinding="{Binding Manufacturer}"/>
</GridView>
</ListView.View>
</ListView>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Occupation" DisplayMemberBinding="{Binding Occupation}"/>
<GridViewColumn Header="Status" DisplayMemberBinding="{Binding Status}"/>
</GridView>
</ListView.View>
</ListView>
This can be improved in terms of alignment, e.g. you could set up a Grid in the DataTemplate with a shared size column to make all lists the same width (making the internal columns align might be a bit hard though)
Further you could define a style to collapse empty lists (which otherwise would show the header without items).

how to dynamically create controls for GridView DataTemplate in WPF?

I have a GridView control:
<GridView>
<GridViewColumn Header="Name" Width="500">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding TypeName}" Header="Type" Width="100" />
</GridView>
for the first column("name"), I would like to have a mechanism that when every record is binded, will be a way(e.g. event), so that I can dynamically add controls to the StackPanel.
for example, my data has a column called AnimalType, if it is a cat, I will add an image to the StackPanel; if it is a cow, I will put a media element to play a movie; if it is a dog, I will put a hyper link, etc.
How can I do that?
Take a look at the DataTemplateSelector class....
like here:
http://www.wpftutorial.net/DataTemplates.html

How to set property only on second column of a ListView?

Introduction
I have a ListView and want to format only the second column. The following XAML code does that:
<ListView x:Name="listview">
<ListView.View>
<GridView>
<GridViewColumn Header="Property" DisplayMemberBinding="{Binding Path=Key}" Width="100"/>
<!-- <GridViewColumn Header="Value" DisplayMemberBinding="{Binding Path=Value}" Width="250">-->
<GridViewColumn Header="Value" Width="250">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Value}" Foreground="CornflowerBlue" AutomationProperties.Name="{Binding Path=Key}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
The one problem I have is that the AutomationProperties.Name property is not being set. I was checking it with the Coded UI Test Builder and the property is empty. The Text and the Foreground property are being set correctly.
Question
Does anyone know why AutomationProperties.Name is not being set?
Additional information
Strangly enough, the following XAML code does set the AutomationProperties.Name
<ListView x:Name="listview">
<ListView.Resources>
<Style TargetType="TextBlock">
<Setter Property="AutomationProperties.Name" Value="{Binding Key}"/>
</Style>
</ListView.Resources>
<ListView.View>
<GridView>
<GridViewColumn Header="Property" DisplayMemberBinding="{Binding Path=Key}" Width="100"/>
<GridViewColumn Header="Value" DisplayMemberBinding="{Binding Path=Value}" Width="250"/>
</GridView>
</ListView.View>
</ListView>
The problem here though is that AutomationProperties.Name is being set on all the columns. But I only want it on the second one because otherwise my Coded UI Test code returns the wrong value (that of the first column, instead of that of the second column which I want).
Don't know if you're aware of this, but a very helpful tool in analyzing these types of problems is Snoop.
In particular, it will highlight (with red) any data binding errors you may have.
I took a look myself and it sure seems as if the first piece of xaml (above) is now working (after you cleared up the syntax error). In Snoop, bound properties are highlighted with a light green.
Here is a screen shot of Snoop showing the property is being set correctly:
And here is a screen shot of Snoop showing the TextBlock (where the property isn't set ... no light green column) on the first column:
And, finally, I've intentionally broken the binding to show you what Snoop shows when something is wrong and you have a data binding error (it is highlighted in red and one of the columns gives you additional information):

Multicolumn listview in WPF at design time

I might sound dumb here, but I want to do something really simple. At design time, I want to add columns to a listview control and add some data to it. I need to add combobox in each column of the listview. The thing I am not able to find is where to mention the column number in the listviewitem. Any help appreciated guys.
<ListView IsSynchronizedWithCurrentItem="True" Margin="8,68,304,188"
BorderThickness="2,2,2,2">
<ListView.View>
<GridView>
<GridViewColumn Width="150" Header="Column1"/>
<GridViewColumn Width="150" Header="Column2"/>
</GridView>
</ListView.View>
<ListViewItem>
</ListViewItem>
</ListView>
Each column in the listviewitem is rendered based on the GridView definition, so there is no real concept of column numbers. What you do is bind objects to the the listview's itemsource and it creates listviewitems from it. Thus, there are a few hoops to jump through.
This link has an example of how to do some simple object data binding. The advantage of this is what binding structure you have for design time can probably be reused for run-time if you set the datacontext/itemsource to an empty object instead of the static one in XAML.
If you're doing this to show examples or you just have a static data source that you want to use, I would recommend using the XmlDataProvider. Then you'd change your ListView to be like this,
<ListView IsSynchronizedWithCurrentItem="True" Margin="8,68,304,188"
BorderThickness="2,2,2,2">
<ListView.View>
<GridView>
<GridViewColumn Width="150" Header="Column1" DisplayMemberPath="{Binding XPath=/A/B}"/>
<GridViewColumn Width="150" Header="Column2" DisplayMemberPath="{Binding XPath=/A/C"/>
</GridView>
</ListView.View>
<ListViewItem>
</ListViewItem>
</ListView>

Resources