Deleting all items from listview - c#

New to Visual Studio, trying to convert a VM deployment GUI I have in another language to a wpf application. I am 80% of the way there, just a couple of questions. The GUI has a number of input fields for the user to fill out. The when a button is clicked those input fields populate a listview. The listview is declared like so:
<ListView x:Name="lstOut" ScrollViewer.HorizontalScrollBarVisibility="Visible" HorizontalAlignment="Left" Height="205" Margin="10,394,0,0" VerticalAlignment="Top" Width="1294"
ItemsSource="{Binding MyItems}" SelectionMode="Single">
<ListView.View>
<GridView>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn Header="CPU" DisplayMemberBinding="{Binding CPU}"/>
<GridViewColumn Header="RAM" DisplayMemberBinding="{Binding RAM}"/>
<GridViewColumn Header="IP Address" DisplayMemberBinding="{Binding IP}"/>
<GridViewColumn Header="Subnet" DisplayMemberBinding="{Binding Subnet}"/>
<GridViewColumn Header="Port Group" DisplayMemberBinding="{Binding PortGroup}"/>
<GridViewColumn Header="Gateway" DisplayMemberBinding="{Binding Gateway}"/>
<GridViewColumn Header="DNS" DisplayMemberBinding="{Binding DNS}"/>
<GridViewColumn Header="Description" DisplayMemberBinding="{Binding Description}"/>
<GridViewColumn Header="Template" DisplayMemberBinding="{Binding Template}"/>
<GridViewColumn Header="Host" DisplayMemberBinding="{Binding Host}"/>
<GridViewColumn Header="Site Code" DisplayMemberBinding="{Binding Site}"/>
<GridViewColumn Header="Folder" DisplayMemberBinding="{Binding Folder}"/>
<GridViewColumn Header="DataStore" DisplayMemberBinding="{Binding Datastore}"/>
<GridViewColumn Header="Patch Method" DisplayMemberBinding="{Binding Patch}"/>
<GridViewColumn Header="HDD1 Size" DisplayMemberBinding="{Binding HDD1Size}"/>
<GridViewColumn Header="HDD1 Format" DisplayMemberBinding="{Binding HDD1Format}"/>
<GridViewColumn Header="HDD2 Size" DisplayMemberBinding="{Binding HDD2Size}"/>
<GridViewColumn Header="HDD2 Format" DisplayMemberBinding="{Binding HDD2Format}"/>
<GridViewColumn Header="HDD3 Size" DisplayMemberBinding="{Binding HDD3Size}"/>
<GridViewColumn Header="HDD3 Format" DisplayMemberBinding="{Binding HDD3Format}"/>
<GridViewColumn Header="HDD4 Size" DisplayMemberBinding="{Binding HDD4Size}"/>
<GridViewColumn Header="HDD4 Format" DisplayMemberBinding="{Binding HDD4Format}"/>
<GridViewColumn Header="HDD5 Size" DisplayMemberBinding="{Binding HDD5Size}"/>
<GridViewColumn Header="HDD5 Format" DisplayMemberBinding="{Binding HDD5Format}"/>
</GridView>
</ListView.View>
For adding the collection of items from the GUI to the listview, as well as exporting to csv later in the code, I declared a collection like so:
public ObservableCollection<MyItem> MyItems { get; set; } = new ObservableCollection<MyItem>();
I am able to delete a selected item from the listview in this manner, which seems to work well:
private void DeleteRow(object sender, RoutedEventArgs e)
{
MyItem line = lstOut.SelectedItem as MyItem;
if (line != null)
MyItems.Remove(line);
}
What I am stuck on (one of the things anyway), is deleting everything from the listview. I tried both of these methods:
lstOut.Items.Clear();
lstOut.Items.Remove(MyItems);
But get an error either way that this is not valid when ItemsSource is in use. I tried lstOut.ItemsSource, but could not find a way to clear all content.
I ended up doing it like this, which seems to work (marginally):
for (int i=0; i < lstOut.Items.Count; i++)
{
MyItems.Remove(MyItems[i]);
}
The problem with this method is that is removes half the item count with each button click. If I have 9 items in the listview it cuts it down to 4, another click cuts it down to 2, then 1, then finally deletes.
Can anyone suggest an easier way to delete all content in one action? I am sure it is something stupid simple I am missing, but would appreciate any suggestions.

ICollection<T> in general and ObservableCollection in particular have method Clear()
so the correct way (and the only way when you follow MVVM) is
MyItems.Clear();
using Clear with ObservableCollection is much more effective than multiple calls to Remove, because ObservableCollection raises notifications when items inside are added/removed/replaced. One notification about Clear is faster than numerous notifications about Remove
why this code acts weirdly?
for (int i = 0; i < lstOut.Items.Count; i++)
{
MyItems.Remove(MyItems[i]);
}
let's say initial state is [1,2,3,4], i = 0, lstOut.Items.Count = 4
after first iteration is becomes [2,3,4], i = 1, lstOut.Items.Count = 3
so i points to item 3 !
item 2 was skipped !
a correct loop should be reversed (from last item in collection to first)
for (int i = MyItems.Count - 1; i >= 0; i--)
{
MyItems.RemoveAt(i);
}
or another way is to remove items at 0 position, while there items:
while(MyItems.Count > 0)
{
MyItems.RemoveAt(0);
}

Related

How to connect to database, edit data and show them on listview in WPF

I am creating application like task manager. I have my task saved in database and I want to show them in my apllication and add some new.
How to connect to db and bind data to observable collection to show them in listView? And how can I would add new record to database?
I have this.
Adding to observable collection works properly.
Code:
public TheTaskViewModel()
{
// Initial task with default values
Task = new TheTask
{
Id = 0,
Priority = Priority.Normal,
Status = Status.New
};
// Observable collection of tasks to notify UI
Tasks = new ObservableCollection<TheTask>();
}
private void SubmitExecute(object parameter)
{
Tasks.Add(Task);
}
xaml:
<ListView ItemsSource="{Binding Tasks}" Width="Auto" Margin="0,175,0,0">
<ListView.View>
<GridView>
<GridViewColumn Header="Id" DisplayMemberBinding="{Binding Id}" Width="Auto"/>
<GridViewColumn Header="Priorytet" DisplayMemberBinding="{Binding Priority}" Width="Auto"/>
<GridViewColumn Header="Status" DisplayMemberBinding="{Binding Status}" Width="Auto"/>
<GridViewColumn Header="Termin" DisplayMemberBinding="{Binding Term}" Width="80"/>
<GridViewColumn Header="Treść" DisplayMemberBinding="{Binding Content}" Width="Auto"/>
</GridView>
</ListView.View>
</ListView>

Create a click event on ListViewItem programmatically in WPF

I'm making a WPF app, this app has a UserControl, which has a list view.
I tried to create a click event listener but i never got it to work right, and i havend find anything to solve it
I fill this list view items with an object like this:
List<AsesoriaClass> listaAsesorias = phpClass.getListaAsesoriasAsesor(asesor.ID);
foreach (var asesoria in listaAsesorias)
{
AsesoriaTable data = new AsesoriaTable(asesoria.AsesoriaID.ToString(), asesoria.ClienteNombre + " " + asesoria.ClienteApellidos, asesoria.FechaInicio.ToString(), asesoria.FechaFinal.ToString());
this.ListView.Items.Add(data);
}
And this is the XAML of the User Control:
<ListView x:Name="ListView">
<ListView.View>
<GridView>
<GridViewColumn Header="ID" DisplayMemberBinding="{Binding Path=Id}" Width="100"/>
<GridViewColumn Header="Cliente" DisplayMemberBinding="{Binding Path=Cliente}" Width="300"/>
<GridViewColumn Header="Inicio" DisplayMemberBinding="{Binding Path=Inicio}" Width="200"/>
<GridViewColumn Header="Final" DisplayMemberBinding="{Binding Path=Final}" Width="200"/>
</GridView>
</ListView.View>
</ListView>
I want to make a click listener so, when i click on an item something happens (to start i just want it to show a mesage box). how do i do this?
You can simply attach an Event Handler on SelectionChanged. Like this
ListView.SelectionChanged += LstOnSelectionChanged;
Where LstOnSelectionChanged is a method.
private void LstOnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
MessageBox.Show("Anything");
}

Not able to display ListView item to textbox

Hi all. When ListView item is double clicked it should display the corresponding data to text box, later i will write some code to update.
<p>Below is listview code on my xaml file</p>
<ListView Margin="534,233,10,18" Name="lvCus" MouseDoubleClick="ListViewItem_DoubleClick">
<ListView.View>
<GridView AllowsColumnReorder="true" ColumnHeaderToolTip="TbCus">
<GridViewColumn Header="CusID" Width="40" DisplayMemberBinding="{Binding Path=CusID}" />
<GridViewColumn Header="fn" Width="120" DisplayMemberBinding="{Binding Path=fn}" />
<GridViewColumn Header="Lastname" Width="120" DisplayMemberBinding="{Binding Path=ln}" />
<GridViewColumn Header="Dob" Width="100" DisplayMemberBinding="{Binding Path=dob}" />
<GridViewColumn Header="Age" Width="60" DisplayMemberBinding="{Binding Path=age}" />
</GridView>
</ListView.View>
</ListView>
Below is code at backend.
private void ListViewItem_DoubleClick(object sender, RoutedEventArgs e)
{
ListViewItem item = lvCus.SelectedItems[0];
txtfn.Text = item.SubItems[1].Text;
txtln.Text = item.SubItems[2].Text;
txtdob.Text = item.SubItems[3].Text;
}
I see red underline near the code lvCus.SelectedItems[0] , Error: cannot implicitly convert type 'object' to 'System.Windows.Controls.ListViewItem'. An explict conversion exists (are you missing a cast?)
Any help would be appreciated. Thanks.
You need to cast to your type of object say Customer
Customer custObj = (Customer)lvCus.SelectedItems[0];
Then you can access the properties
txtfn.Text = custObj.fn;
txtln.Text = custObj.ln;
txtdob.Text = custObj.dob;

Binding a ListView to an ObservableCollection of ArrayList items without named properties

Firstly:
<ListView Height="259" HorizontalAlignment="Left" Margin="7,6,0,0" Name="dataListView" VerticalAlignment="Top" Width="899">
<ListView.View>
<GridView>
<GridViewColumn Width="240" Header="Test" />
<GridViewColumn Width="50" Header="Result" />
<GridViewColumn Header="Column 3" />
</GridView>
</ListView.View>
</ListView>
is the definition in my XAML file.
Then when a test starts, I run:
dataListView.ItemsSource = tr.TestResultCollection;
In TestRunner.cs, I have created the Observable Collection of ArrayLists as such:
ObservableCollection<ArrayList> _testResultCollection = new ObservableCollection<ArrayList>();
and publicly refer to them as such:
public ObservableCollection<ArrayList> TestResultCollection
{ get { return _testResultCollection; } }
Finally when I add to the collection, I use :
_testResultCollection.Add(SummaryVerificationTestCase1(dbs, dbd));
which adds an ArrayList to the collection. (Yes, a collection of ArrayLists, I know...)
However, what gets displayed in each Column is (Collection), (Collection, (Collection).
I see why. However, I'm not entirely certain what the neatest way around is. Normally in each GridViewColumn you give a binding like:
DisplayMemberBinding="{Binding TestResult}"
But the ArrayList doesn't have named components, just indices (0-2).
Is there a way to bind each column to the individual indices? Or have I missed something simple already?
Specify an index in the binding path:
<GridViewColumn Width="240" Header="Test" DisplayMemberBinding="{Binding Path=[0]}"/>
<GridViewColumn Width="50" Header="Result" DisplayMemberBinding="{Binding Path=[1]}"/>
<GridViewColumn Header="Column 3" DisplayMemberBinding="{Binding Path=[2]}"/>

Unable to bind the collection to Listview in WPF application?

I am developing a WPF application where i can read some properties from the windows services list which are currently running on my system.I am able to read the properties of a particular service and passing to a collection which in turn show up in my UI under a Listview.
I want the same scenario to be used for list of services .i.e.i am trying in the following way..but i am not sure where did i miss the point...
Here is my code
foreach (string serviceName in sList)
{
ServiceController controller = new ServiceController(serviceName);
StatusCollection.Add (new StatusData
{
Name = name,
Status = status
});
lvStatus.DataContext = StatusCollection;
lvStatus.ItemsSource = StatusCollection;
}
<ListView Height="166" HorizontalAlignment="Left" Margin="23,0,0,0" Name="lvStatus" VerticalAlignment="Top" Width="264" >
<ListView.View>
<GridView>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}"></GridViewColumn>
<GridViewColumn Header="Status" DisplayMemberBinding="{Binding Status}"></GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Remove the DataContext line of code.
If you set your ItemsSource in the code behind make sure you do it before InitializeComponent is called. If not, you will need to refresh your Items collection.
However, I would setup a View Model for your Window or Control which implements INotifyPropertyChanged. Create your collection as an ObservableCollection and bind to it in the XAML:
<ListView ... ItemsSource={Binding Path=ServiceList}>
<ListView.View>
<GridView>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Path=Name}" />
<GridViewColumn Header="Status" DisplayMemberBinding="{Binding Path=Status}" />
</GridView>
</ListView.View>
</ListView>
Let me know if you need an example of using a View Model.

Categories

Resources