How to fetch all the rows in a listview wpf - 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

Related

AutoComboBox DisplayMemberPath call Converter or Set MultiBinding

In ComboBox ItemSource List Class set one Property that is Object of the class and I have to set in one for display purpose when I selectedItem
<AutoComboBox x:Name="cbPatient" Grid.Row="1" Grid.Column="3" ItemsSource="{Binding Path=Patients}"
SelectedItem="{Binding SelectedPatient}">
<AutoComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name,Converter={StaticResource NameToFullNameConverter}}"/>
</DataTemplate>
</control:AutoComboBox.ItemTemplate>
<control:AutoComboBox.DropDownView>
<GridView>
<GridViewColumn Header="Type" DisplayMemberBinding="{Binding Path=Name,Converter={StaticResource NameToFullNameConverter}}"/>
</GridView>
</control:AutoComboBox.DropDownView>
</control:AutoComboBox>
this converter works in DropDownView, but not work when I select an item from DropDownView
Thanks in advance

How to enable a cell in a disabled row of a WPF ListView

I have a WPF ListView who's view is set to a GridView. Rows in the list are sometimes disabled but I need one column of cells to ALWAYS be enabled. We are displaying a link in the "URL" column and the user needs the ability to click the link even if the row is disabled. Currently, if the row is disabled, the link is disabled as well.
I currently have this in XAML:
<ListView.View>
<GridView>
<GridViewColumn Header="Name">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock
Text="{Binding Item.Name}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Description">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock
Text="{Binding Item.Description}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="URL">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Label>
<Hyperlink
Command="{Binding ViewModel.OpenInstructionsCommand}">
<TextBlock Text="View" />
</Hyperlink>
</Label>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
Although it is not guaranteed to work without side effects for all control types, it is possible to extend the control that you want to remain enabled to ignore the propagation of the IsEnabled property from the parent control. For an example of this with a bit more explanation, see Cedric Dussud's post here.
In this case, your code might look like:
internal class EnabledHyperlink : Hyperlink
{
static EnabledHyperlink()
{
IsEnabledProperty.OverrideMetadata(typeof (EnabledHyperlink),
new UIPropertyMetadata(true,
IsEnabledPropertyChanged,
CoerceIsEnabled));
}
private static void IsEnabledPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs args)
{
}
private static object CoerceIsEnabled(DependencyObject source, object value)
{
return value;
}
}

WPF Listview flickering problem

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

How to get selected item of a nested listview?

i have a nested listview, i can bind the selected item of the basic listview to my viewmodel but not my selected item of the nested listview ( in the basic listview ) I just do:
this is my listview:
<ListView Height="155" ScrollViewer.CanContentScroll="True" ScrollViewer.VerticalScrollBarVisibility="Visible" dd:DragDrop.IsDragSource="True"
dd:DragDrop.IsDropTarget="False" Margin="24,506,280,169" Background="#CDC5CBC5"
dd:DragDrop.DropHandler="{Binding}" SelectedItem ="{Binding Path=SelectedCluster,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" ItemsSource="{Binding Path=Clusters,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" >
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="Titel" DisplayMemberBinding="{Binding Title}"/>
<GridViewColumn Header="Questions">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ListView DataContext="{Binding}" ItemsSource="{Binding ExaminationQuestions}" SelectedItem="{Binding Path=SelectedExaminationQuestionInCluster,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}">
<ListView.View>
<GridView>
<GridViewColumn Header="Description" DisplayMemberBinding="{Binding Question.Description}"/>
</GridView>
</ListView.View>
</ListView>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
Viewmodel:
public ExaminationQuestion SelectedExaminationQuestionInCluster
{
get { return selectedExaminationQuestionInCluster; }
set { selectedExaminationQuestionInCluster = value;
OnPropertyChanged("SelectedExaminationQuestionInCluster");
}
}
Someone who knows what i am doing wrong? If i set a breakpoint of the setter of selecteditem of the second listview. He just ignores that..
Thanks
My guess is the binding is probably incorrect. In your outer ListView, you bind to "Clusters". Your inner ListView is probably trying to bind to "SelectedExaminationQuestionInCluster" on the current Cluster. You can see if this is the case by using snoop. It's a valuable tool when debugging WPF apps. It will highlight broken bindings in red and tell you what's wrong with them.
If you want to bind to "SelectedExaminationQuestionInCluster" on the parent DataContext, you could use this syntax:
SelectedItem="{Binding Path=DataContext.SelectedExaminationQuestionInCluster,
ElementName=OuterListView}"
You'll have to give the outer ListView a name of course.
EDIT: I just realized this might not make sense. If each Cluster has its own collection of ExaminationQuestions, then each Cluster should also have a SelectedExaminationQuestion. The parent DataContext should not have any concept of a SelectedQuestion unless it is shared amongst all Clusters.

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>

Resources