WPF Listview flickering problem - wpf

I am using a thread for reading the file and make a array of objects from the data read.A seperate thread for filtering records based on some filters is being used.
I am using listview to show data for dataset I get as per above.
While laoding a file everthing seems good but when I search,the problem exists.
while searching when I apply filters for the 1st time, everything is okay. Now again when I apply filters, data of the previous search is show for 1 sec(kind of flicker) and then the new data according to current filter is rendered.
I am using dispatcher for updating UI.
Before I bind any data, I try to clear ListView ItemSource by setting it to null
XAML code i am using is :
{
<ListView Name="listView1"
Grid.Row="0"
ItemsSource= "{Binding ElementName=Window1, Path=Entries}"
AllowDrop="True"
SelectionChanged="listView1_SelectionChanged"
Drop="listView1_Drop">
<ListView.View>
<GridView x:Name="GridView1" >
<GridViewColumn Header="Item" DisplayMemberBinding="{Binding Item}" />
<GridViewColumn Header="TimeStamp" DisplayMemberBinding="{Binding TimeStamp}"/>
<GridViewColumn Header="">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding Image}" Width="16" Height="16" VerticalAlignment="Top" HorizontalAlignment="Left"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Level" DisplayMemberBinding="{Binding Level}"/>
<GridViewColumn Header="Class" DisplayMemberBinding="{Binding Class}"/>
<GridViewColumn Header="Message" DisplayMemberBinding="{Binding Message1}" Width="250" />
</GridView>
</ListView.View>
</ListView>
}
Code Behind is :
private void ClearListView()
{
UpdateList update = new UpdateList(UpdateListData);
List<LogEntry> searcheddata = new List<LogEntry>();
searcheddata = null;
listView1.ItemsSource = null;
listView1.Items.Clear();
listView1.Items.Refresh();
pdDispatcher.BeginInvoke(update, DispatcherPriority.Render, searcheddata);
}
psdispatcher is the dispatcher used to update the UI & searchdata is function to assign datasource to listview

Related

Populating a list view, from view model class in WPF

I am trying to add a list of model objects to my list view
This is my View Code which contains a list view as a Grid View
<ListView Grid.Row="8" Grid.ColumnSpan="3" Name="EmployeeDetailsListView">
<ListView.View>
<GridView>
<GridViewColumn Header="{x:Static resx:Resources.String1}" DisplayMemberBinding="{Binding EmployeeID}"></GridViewColumn>
<GridViewColumn Header="{x:Static resx:Resources.String2}" DisplayMemberBinding="{Binding FirstName}"></GridViewColumn>
<GridViewColumn Header="{x:Static resx:Resources.String3}" DisplayMemberBinding="{Binding LastName}"></GridViewColumn>
<GridViewColumn Header="{x:Static resx:Resources.String10}" DisplayMemberBinding="{Binding Gender}"></GridViewColumn>
<GridViewColumn Header="{x:Static resx:Resources.String11}" DisplayMemberBinding="{Binding Phone}"></GridViewColumn>
<GridViewColumn Header="{x:Static resx:Resources.String7}" DisplayMemberBinding="{Binding Phone}" ></GridViewColumn>
<GridViewColumn Header="{x:Static resx:Resources.String8}" DisplayMemberBinding="{Binding Phone}" ></GridViewColumn>
</GridView>
</ListView.View>
</ListView>
My View Model Contains the following code
List<EmployeeModel> eList = new List<EmployeeModel>();
eList.Add(EmployeeModel);
EmployeeDetailsListView.ItemsSource = eList;
I am trying to populate the List View from the View Model, but the ListView is not getting recognised in the ViewModel Class
I am getting the following error
"The name 'EmployeeDetailsListView' does not exist in the current context "
I want to know how to access ListView present in View.xaml from my ViewModel, so that I can populate the list view.
Thanks in Advance :)

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

Custom view listview Binding WPF

Hi I have next XAML markup (just a piece of course):
<Window.Resources>
<GridView x:Key="gridview">
<GridViewColumn Width="200" DisplayMemberBinding="{Binding Title}">
<GridViewColumnHeader Content="Titel" Tag="Title" Click="SortClick"/>
</GridViewColumn>
<GridViewColumn Width="200" DisplayMemberBinding="{Binding Artist}">
<GridViewColumnHeader Content="Artiest" Tag="Artist" Click="SortClick"/>
</GridViewColumn>
<GridViewColumn Width="200" DisplayMemberBinding="{Binding Album}">
<GridViewColumnHeader Content="Album" Tag="Album" Click="SortClick"/>
</GridViewColumn>
<GridViewColumn Width="50" DisplayMemberBinding="{Binding Genre}">
<GridViewColumnHeader Content="Genre" Tag="Genre" Click="SortClick"/>
</GridViewColumn>
<GridViewColumn Width="50" DisplayMemberBinding="{Binding Jaar}">
<GridViewColumnHeader Content="Jaar" Tag="Jaar" Click="SortClick"/>
</GridViewColumn>
</GridView>
<my:IdToImageConverter x:Key="idToImageConverter" />
<DataTemplate x:Key="iconTemplate">
...
</DataTemplate>
<my:PlainView x:Key="iconView"
ItemTemplate="{StaticResource iconTemplate}"
ItemWidth="300"/>
</Window.Resources>
<Grid>
<ListView Name="LibView" ItemsSource="{Binding ElementName=win, Path=Biblio}"/>
</Grid>
Biblio is the observable collection containing the elements for LibView
iconView and gridview are the views i use for LibView. This works perfectly.
Now i want to add a view wich groups every element by "Artist", and i want to display this like:
Artist1 - TitleA - AlbumA
- TitleB - AlbumB
- TitleC - AlbumC
Artist2 - TitleD - AlbumD
...
I guess i have to make some kind of template but i don't even know if this is possible using XAML.
It sound like you want a GroupStyle - this might explain:
http://bea.stollnitz.com/blog/?p=17
There are many examples - try a search on wpf groupstyle :)

ListView column auto sizing

Let's say I have the following ListView:
<ListView ScrollViewer.VerticalScrollBarVisibility="Auto">
<ListView.View>
<GridView>
<GridViewColumn Header="Something"
DisplayMemberBinding="{Binding Path=ShortText}" />
<GridViewColumn Header="Description"
DisplayMemberBinding="{Binding Path=VeryLongTextWithCRs}" />
<GridViewColumn Header="Something Else"
DisplayMemberBinding="{Binding Path=AnotherShortText}" />
</GridView>
</ListView.View>
</ListView>
I'd like the short text columns to always fit in the screen, and the long text column to use the remaining space, word-wrapping if necessary.
Is that possible?
There is no easy way to do this with a GridListView since it doesn't support setting the width of a column to "*" (fill remaining space).
Here is a discussion of how you could fake it by using an IValueConverter to set the width of the column to TotalListWidth - SumOfColumnWidths
On the other hand, have you considered using a DataGrid instead? This will support the kind of layout you are looking for, though is a considerably heavier control. It is also only native in .NET 4 - though you can get an equivalent for 3.5 through the WPF Toolkit.
Set Width="Auto" on your GridViewColumns. However, due to virtualization you may encounter some problems with auto-sizing.
See this question.
So, long-story-short, if you want accurate auto-sizing of columns you'll need to recalculate your widths when the visible data changes, due to virtualization.
<Grid Name="dummygrid" Visibility="Hidden">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*"></ColumnDefinition>
<ColumnDefinition Width="0.2*"></ColumnDefinition>
<ColumnDefinition Width="0.1*"></ColumnDefinition>
<ColumnDefinition Width="0.2*"></ColumnDefinition>
<ColumnDefinition Width="150"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Name="dummywidth1"></Border>
<Border Grid.Column="1" Name="dummywidth2"></Border>
<Border Grid.Column="2" Name="dummywidth3"></Border>
<Border Grid.Column="3" Name="dummywidth4"></Border>
<Border Grid.Column="5" Name="dummywidth5"></Border>
</Grid>
<ListView Name="Installer_LV" Grid.Row="1" ItemContainerStyle="{StaticResource LV_ItemStyle}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" AlternationCount="2">
<ListView.View>
<GridView ColumnHeaderContainerStyle="{StaticResource LV_HeaderStyle}">
<GridViewColumn Width="{Binding ElementName=dummywidth1, Path=ActualWidth}" DisplayMemberBinding="{Binding DisplayName}" >
<GridViewColumn.Header>
<GridViewColumnHeader Tag="DisplayName" Click="InstallerLV_HeaderClick">Name</GridViewColumnHeader>
</GridViewColumn.Header>
</GridViewColumn>
<GridViewColumn Width="{Binding ElementName=dummywidth2, Path=ActualWidth}" DisplayMemberBinding="{Binding Publisher}">
<GridViewColumn.Header>
<GridViewColumnHeader Tag="Publisher" Click="InstallerLV_HeaderClick">Publisher</GridViewColumnHeader>
</GridViewColumn.Header>
</GridViewColumn>
<GridViewColumn Width="{Binding ElementName=dummywidth3, Path=ActualWidth}" DisplayMemberBinding="{Binding Version}">
<GridViewColumn.Header>
<GridViewColumnHeader Tag="Version" Click="InstallerLV_HeaderClick">Version</GridViewColumnHeader>
</GridViewColumn.Header>
</GridViewColumn>
<GridViewColumn Width="{Binding ElementName=dummywidth4, Path=ActualWidth}" DisplayMemberBinding="{Binding Size}">
<GridViewColumn.Header>
<GridViewColumnHeader Tag="Size" Click="InstallerLV_HeaderClick">Size</GridViewColumnHeader>
</GridViewColumn.Header>
</GridViewColumn>
<GridViewColumn Header="Action" Width="150">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button Height="38" Width="130" Style="{DynamicResource RoundedButton}" Content="{Binding Status}" Tag="{Binding ModuleId}" HorizontalAlignment="Center" VerticalAlignment="Center" Click="onActionClick"></Button>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
In the above example i have used a dummy grid and split into 5 columns and using binding assign that size to "GridViewColum" by
Width="{Binding ElementName=dummywidth4, Path=ActualWidth}"
So that when the hidden dummy grid column size changes it will get reflect in gridview column size also.
This works for me, toggling the Width to ActualWidth and then back to NaN for any columns that don't have widths explicitly set. This will only work if the listview columns do not contain controls. I usually call this after data in the list has changed.
Public Shared Sub AutoResizeListView(lst As Windows.Controls.ListView)
Dim gv = DirectCast(lst.View, Windows.Controls.GridView)
For Each gvc In gv.Columns
If Double.IsNaN(gvc.Width) Then
gvc.Width = gvc.ActualWidth
gvc.Width = Double.NaN
End If
Next
End Sub
First set the name in the column header like so:
<GridViewColumn Header="Description" Width="350" x:Name="lvhDescription"/>
And then on resize modify width.
Private Sub winMain_SizeChanged(sender As Object, e As SizeChangedEventArgs) Handles Me.SizeChanged
If Me.IsLoaded = False Then Exit Sub
lvhDescription.Width = e.NewSize.Width - 665
End Sub
I'd like to present an another approach in order to size each column with the largest element width.
Do this following on each list view item with the help of a loop.
No need to change size after a re-size window event.
Leaves UnitWidth as the constant font width size.
You can also define a delegate to the SourceUpdated event.
GridView gv = (myListView.View as GridView);
if (titleLen < c.Title.Length)
{
titleLen = c.Title.Length;
gv.Columns[0].Width = titleLen * UnitWidth;
}
if (cssLen < c.CSSName.Length)
{
cssLen = c.CSSName.Length;
gv.Columns[1].Width = cssLen * UnitWidth;
}
if (valueLen < c.Value.Length)
{
valueLen = c.Value.Length;
gv.Columns[2].Width = valueLen * UnitWidth;
}
Try this code instead,
private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{
double remainingSpace = mylistviewname.ActualWidth;
if (remainingSpace > 0)
{
(mylistviewname.View as GridView).Columns[1].Width = Math.Ceiling(remainingSpace / 3);
(mylistviewname.View as GridView).Columns[2].Width = Math.Ceiling(remainingSpace / 3);
(mylistviewname.View as GridView).Columns[3].Width = Math.Ceiling(remainingSpace / 3);
}
}
Here i user SizeChanged event so when the windows size change this function is triggered and update the width of the listviewheader. I have 3 listviewheaders so divided by 3 if you have more than 3 divide by appropriate value.
<ListView ScrollViewer.VerticalScrollBarVisibility="Auto" Name="someList">
<ListView.View>
<GridView>
<GridViewColumn Width={Binding ElementName=someList, Path=ActualWidth/3} Header="Something" DisplayMemberBinding="{Binding Path=ShortText}" />
<GridViewColumn Width={Binding ElementName=someList, Path=ActualWidth/3} Header="Description" DisplayMemberBinding="{Binding Path=VeryLongTextWithCRs}" />
<GridViewColumn Width={Binding ElementName=someList, Path=ActualWidth/3} Header="Something Else" DisplayMemberBinding="{Binding Path=AnotherShortText}" />
</GridView>
</ListView.View>
</ListView>

How to fetch all the rows in a listview wpf

I have a list view which has a grid view with four columns. The itemsSource for the listview is an IList(Of SomeType). Each cell in the grid contains a checkboxes, which are checked/unchecked based on the values in the bound property. Now i want to retrieve all the rows in list/grid view for saving purposes or atleast all those checkboxes that are checked. I couldn't find a suitable way to do that.
Here is how i create my listview.
<ListView Margin="10, 40, 95, 10" x:Name="ListViewPane">
<ListView.View>
<GridView x:Name="gridColumns">
<GridViewColumn Width="auto" Header="Right" DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn Width="auto" Header="Read">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox Margin="0" VerticalAlignment="Center" IsChecked="{Binding CanRead}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Width="auto" Header="Write">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox Margin="0" VerticalAlignment="Center" IsChecked="{Binding CanWrite}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Width="auto" Header="Delete">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox Margin="0" VerticalAlignment="Center" IsChecked="{Binding CanDelete}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Can anyone help me????
You can iterate through the Items object of the ListView to get the values:
foreach( var item in this.ListViewPane.Items )
{
var ofSomeType = item as OfSomeType;
if( ofSomeType != null )
{
string name = ofSomeType.Name;
bool canDelete = ofSomeType.CanDelete;
bool canRead = ofSomeType.CanRead;
bool canWrite = ofSomeType.CanWrite;
// do stuff with your Of Some Type objects
}
}
You need to set the IsChecked Bindings to Mode=TwoWay, e.g.
IsChecked="{Binding CanRead, Mode=TwoWay}"
Then WPF will update your business objects as the user checks and unchecks the boxes.
Now you can just collect the values directly from your business object collection (the ItemsSource):
For Each busobj In ListViewPane.ItemsSource
If busobj.CanDelete Then
' whatever
End If
Next
(pardon any syntax errors in the VB)
If you really need to access the ListViewItem controls that represent the physical rows in the UI control, you can get at them using the ItemContainerGenerator:
For Each busobj In ListViewPane.ItemsSource
Dim lvi As ListViewItem = CType(ListViewPane.ItemContainerGenerator.ContainerFromItem(busobj), ListViewItem)
Next

Resources