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");
}
Related
I have a ListView that gets its values from a database, with the last column being buttons. What I am trying to do, is that when a button is clicked, the value of the Name in the same row will be returned.
Here's the relevant part of my XAML code:
<Grid Grid.ColumnSpan="2">
<ListView Name="PeopleList">
<ListView.View>
<GridView>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding [Name]}" />
<GridViewColumn Header="Phone" DisplayMemberBinding="{Binding [Phone]}" />
<GridViewColumn Header="Email" DisplayMemberBinding="{Binding [Email]}" />
<GridViewColumn Header="Actions" Width="200">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button Content=">" Click="ActionButton_Click"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
You should be able to get the exact Button that was clicked from the sender argument of the Click event. From there you should be able to get Button.DataContext, which would hold a reference to the item that is being displayed on that row.
It would be something like:
private void ActionButton_Click(object sender, EventArgs args)
{
var rowItem = (sender as Button).DataContext as People;
string name = rowItem.Name;
}
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);
}
I can get events from everything under the headers, but I can't get an event from clicking the headers. Here's the XAML; notice the event is for the entire ListView, so it should activate when anything is clicked:
<ListView x:Name="myListView" MouseLeftButtonUp="myListView_MouseLeftButtonUp" Margin="10">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="File Path"
DisplayMemberBinding="{Binding Path=Path}" />
<GridViewColumn Header="File Size"
DisplayMemberBinding="{Binding Path=Size}" />
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
And the event itself is very simple. Just show me that something has happened:
private void myListView_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
string output = sender.ToString();
MessageBox.Show(output);
}
Clicking anywhere under the headers responds perfectly:
"System.Windows.Controls.ListView Items.Count:0"
Clicking the "File Path" header does nothing. Clicking the "File Size" header does nothing.
MSDN says:
https://msdn.microsoft.com/en-us/library/vstudio/ms745786(v=vs.100).aspx
<ListView x:Name='lv' Height="150" HorizontalAlignment="Center" VerticalAlignment="Center"
GridViewColumnHeader.Click="GridViewColumnHeaderClickedHandler">
Visual Studio says there's no such thing as GridViewColumnHeader, so none of the code on MSDN works.
That's how WPF UI events work by default. They bubble up. If somebody eats the message along the way (which is what button type controls do), the higher level controls won't get it. You can either use the Preview version of the event, or the cleaner way to do it:
AddHandler(GridViewColumnHeader.ClickEvent, new RoutedEventHandler(ListView_OnColumnClick));
<GridViewColumn Width="150" >
<GridViewColumn.Header>
<GridViewColumnHeader Click="GridViewColumnHeader_Click">click me</GridViewColumnHeader>
</GridViewColumn.Header>
</GridViewColumn>
Even if a bit late, but in XAML you can do something like:
<!-- ListView -->
<GridView AllowsColumnReorder="True">
<GridViewColumn Width="220">
<GridViewColumnHeader Content="{DynamicResource ResourceKey=explorer_column_name}" Command="{Binding Path=ISortBy}" CommandParameter="{x:Static enu:SortType.Name}"/>
<GridViewColumn.CellTemplate>
//...
</GridViewColumn.CellTemplate>
</GridViewColumn>
//..
</GridView>
AddHandler should be called on the ListView, like:
myListView.AddHandler(GridViewColumnHeader.ClickEvent, new RoutedEventHandler(myListView_OnColumnClick));
Then e.OriginalSource can be casted to GridViewColumnHeader in your myListView_OnColumnClick and you can identify your column.
Been messing with this and can't seem to figure it out. It seems that the object sender is actually the ListView.. so even though if I figure out how to get the GridViewColumn as a child... I don't know how to distinguish which column was actually clicked?
<ListView x:Name="SingleTweet_ListView"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
MouseLeftButtonUp="SingleTweet_ListView_MouseLeftButtonUp"
Height="200" Margin="5,5,5,5" FontSize="12"
GridViewColumnHeader.Click="GridViewColumnHeaderClickedHandler">
<ListView.View>
<GridView>
<GridViewColumn Header="Screen Name"
DisplayMemberBinding="{Binding Col1}" Width="112"/>
<GridViewColumn Header="Tweet"
DisplayMemberBinding="{Binding Col2}" Width="623"/>
</GridView>
</ListView.View>
</ListView>
void GridViewColumnHeaderClickedHandler(object sender, RoutedEventArgs e)
{
MessageBox.Show(((GridViewColumn)sender).Header.ToString());
//error cus the sender is actually the listview?
}
Sender will be ListView but you can check for OriginalSource which will be GridViewColumnHeader and can get column from it:
MessageBox.Show(((GridViewColumnHeader)e.OriginalSource).Column
.Header.ToString());
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.