I have a listview with three columns, When I select a listview item, how can I access the TextBox of the selected item?
In my case I would like to focus the TextBox "textQuantity" when I select an item.
<ListView x:Name="EntryListView" Height="Auto"
ItemsSource="{Binding TheList}"
MouseDoubleClick="EntryListView_MouseDoubleClick"
SelectionChanged="EntryListView_SelectionChanged">
<ListView.View>
<GridView>
<GridViewColumn Header="Quantity">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBox Name="textQuantity" Text="{Binding DefaultQuantity}" Width="40" IsTabStop="True"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Block1">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Block1}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Block2" Width="Auto">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Block2}"></TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
I Guess I need to do something in Selectionchanged?
private void EntryListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
}
UPDATE:
Just trying to explain more:
When I select the first row of the listview, by tabing into it, or selecting the row by left click. I want to be able to write into the Quantity-TextBox of the selected ListView item.
For example, If I press on Test1, I want to directly be able to write into the field where the text is 100. Now I have to press inside the TextBox to be able to edit the value.
You're binding the item source to a collection, create a property of the same type as your collection. Then bond your listbox selecteditem to that property.
Alternatively bind to a selected index property.
Either gives you a way to identify which item in the collection is selected.
Related
I have this problem with my C# WPF app:
I have the checkboxes on every row but when I select (random) one or more checkboxes I noticed that other checkboxes on other rows (when I scroll to see the other rows) are selected, too. It's like there would be a function or something that checks automatically other checkbox different of those selected by me.
There is no C# code for the checkboxes (just the definitions of the functions for Checked, Unchecked). I use a query and ItemSource to fill the Datagrid.
So, is there a way to avoid the automatic selection of other checkboxes ?
Thankx
My XAML code:
<DataGridTemplateColumn x:Name="colonnaChiusoF" Header="Cf" Width="26">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Path=sc1, Mode=TwoWay}" Checked="checkedF" Unchecked="uncheckedF" Margin="0" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Actually it happens with other objects, too. For example, in this code the buttons and checkboxes are selected automatically random if I select/deselect some of them:
<ListView Name="listaView" ItemsSource="{Binding Path=Table}" Height="200" Width="400" ScrollViewer.VerticalScrollBarVisibility="Visible" IsSynchronizedWithCurrentItem="True" Background="{x:Null}" BorderBrush="{x:Null}" Foreground="{x:Null}">
<ListView.View>
<GridView>
<GridViewColumn Header="Idprev" DisplayMemberBinding="{Binding Path=idPrev}" />
<GridViewColumn Header="DataPrev" DisplayMemberBinding="{Binding Path=dataPrev}" />
<!--<GridViewColumn Header="Test3" DisplayMemberBinding="{Binding Test3}" /> -->
<GridViewColumn Header="Chiudi">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox Margin="0" BorderThickness="0" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Button">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ToggleButton IsChecked="True">Button Text</ToggleButton>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
The C# code:
DbDataAdapter da = daoObject.list_3(0, 0, arrayFilter);
DataSet dataset = new DataSet();
da.Fill(dataset);
listaView.DataContext = dataset.Tables[0].DefaultView;
Well, the problem should be the virtualization. If I UNCHECK "Enable row virtualization" it seems the checkboxes remain as I select them so there is no random automatically check-uncheck.
The problem now is that the records are loaded slower than with the virtualization enabled.
i'm having a few problems working with a gridview and a combobox inside of it.
Here is the code for my ListView control:
<ListView Height="139" HorizontalAlignment="Left" Margin="10,158,0,0" Name="lvAppointment" VerticalAlignment="Top" Width="250" MinWidth="350">
<ListView.View>
<GridView>
<GridViewColumn Header="Appointment" Width="120">
<GridViewColumn.CellTemplate>
<DataTemplate>
<DatePicker SelectedDate="{Binding Path=Appointment}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Type" Width="170">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ComboBox ???/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Done" Width="50">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Path=Done}" IsThreeState="False"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
I'm popluating the list from a sql ce database via c# with the following code
using (SqlCeCommand sqlCeAppointment = new SqlCeCommand("SELECT appid,appointment,done,apptype.type FROM appointment INNER JOIN apptype ON appointment.refatid = apptype.atid WHERE refeventid = #eventid;", sqlCeConn))
{
sqlCeAppointment.Parameters.AddWithValue("#eventid", ((cListEventItem)lvEvent.SelectedItems[0]).id);
using (SqlCeDataReader sqlCeAppointmentReader = sqlCeAppointment.ExecuteReader())
{
lvAppointment.Items.Clear();
while (sqlCeAppointmentReader.Read())
{
lvAppointment.Items.Add(new cListAppointmentItem { id = sqlCeAppointmentReader.GetGuid(sqlCeTerminReader.GetOrdinal("appid")), Appointment = sqlCeAppointmentReader.GetDateTime(sqlCeTerminReader.GetOrdinal("appointment")), Type = sqlCeAppointmentReader.GetString(sqlCeTerminReader.GetOrdinal("type")), Done = sqlCeAppointmentReader.GetByte(sqlCeTerminReader.GetOrdinal("done")) });
}
}
}
I can popluate the list just fine. But i want "Type" to be a combobox so the user can select the apropriate type of the appointment (its a list of appointments connected to an event). This combobox should be filled with data thats inside a table of the sql ce database (apptype). This table is not static, the users can add and delete items from this list.
I have tried a few ways i found via google, but failed. I guess i'm having problems understanding how this works/should work.
I hope someone can help me :(
Thanks in advance
I would suggest getting a list of appointment-types on the MainViewModel. Then bind the ItemsSource of the ComboBox to that List and bind the SelectedItem to the AppointmentItem type.
<UserControl x:Name="TheUserControl">
<ListView>
<GridView>
<GridViewColumn Header="Type" Width="170">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding ElementName=TheUserControl, Path=AppointmentTypes}"
SelectedItem="{Binding Path=Type}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView>
</UserControl>
You can do it by defining a property of type ObservableCollection.
If the data type of the collection is string then you can define it as:
public ObservableCollection<string> Types
{
get
{
ObservableCollection<string> _types = new ObservableCollection<string>();
_types.Add("value1");
_types.Add("value2");
_types.Add("value3");
return _types;
}
}
In your XAML you can bind it as:
<ComboBox VerticalAlignment="Top" HorizontalAlignment="Left" ItemsSource="{Binding Path=Types}" SelectedItem="{Binding MainViewModel.Type,Mode=TwoWay}" SelectedValue="{Binding SelectedValue}" Width="300" ></ComboBox>
I have a this code:
<ListView Height="238"
HorizontalAlignment="Left"
Name="listView1"
VerticalAlignment="Top"
Width="503"
ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="True">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox Tag="{Binding ID}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding ID}" Header="ID" />
<GridViewColumn DisplayMemberBinding="{Binding Name}" Header="Name" />
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
That produce this window:
How do I know how many checkboxes are selected, and get the value Tag of each CheckBox that is selected?
i know it's old but for posterity if people stubble upon this here's the solution
<ListView Height="238"
HorizontalAlignment="Left"
Name="listView1"
VerticalAlignment="Top"
Width="503"
ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="True"
SelectionChanged="listView1_SelectionChanged">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox Tag="{Binding ID}" IsChecked="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListViewItem}}, Path=IsSelected}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding ID}" Header="ID" />
<GridViewColumn DisplayMemberBinding="{Binding Name}" Header="Name" />
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
then in the cs file code this in the listView1_SelectionChanged
private List<MyObject> lstMyObject = new List<MyObject>();
private void listView1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
foreach (MyObject item in e.RemovedItems)
{
lstMyObject.Remove(item);
}
foreach (MyObject item in e.AddedItems)
{
lstMyObject.Add(item);
}
}
lstMyObject should be same type as your object binded to the list. and the code will simply add and remove reference to items of the original list to that list.
Now all you will have to do is loop through that list which will contain only the actually selected items. this works for single selection only except that the lstMyObject will just contain 1 record all the time.
It should be as simple as binding the IsChecked property of the CheckBox to a property on the ViewModel (you may need to add a new property if it doesn't already exist). Then, once the button is clicked, you would just iterate over all the items in the collection, and delete the ones that are checked (based on the value of the property on the ViewModel).
A suggestion...
Just like the Tag property in all Windows controls, I've always had a Tag property in all my data models for general purpose use at run-time. I use that property to hold checked state of the item in a ListView. In other circumstance, I use them to hold complex objects as well.
If I were to say "the heck with it!", I could just give my ListView with SelectionMode="Multiple" a name, and be able to get all of the selected items very easily. But I'm trying to stick to MVVM as much as possible, and I want to somehow databind to an ObservableCollection that holds the value from the Name column for each selected item. How in the world do you do this? Single selection is simple, but the multi selection solution is not obvious to me with my current WPF / MVVM knowledge.
I read this question on SO, and while it does give me some good insight, I don't know how to add the necessary binding to a row, because I am using a ListView with a GridView as its View, not a ListBox.
Here's what my XAML basically looks like:
<ListView DockPanel.Dock="Top" ItemsSource="{Binding ClientPreview}" SelectionMode="Multiple">
<ListView.View>
<GridView AllowsColumnReorder="False">
<GridViewColumn Header="Name">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Address">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Address}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
It sounds like the right thing to do is to databind each row's IsSelected property to each object stored in the ObservableCollection I'm databinding to. I just haven't figured out how to do this.
Write ItemContainerstyle on the ListView and put a Setter to do the binding to your ViewModel 'IsSelected' property
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected,Mode=OneWayToSource}"/>
I have the following XAML class:
<ListView Controls:ListViewColumns.Stretch="true"
Name="myListItems" SelectionMode="Single">
<ListView.View>
<GridView>
<GridViewColumn Width="50">
<GridViewColumn.Header>
</GridViewColumn.Header>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button Name="btnDelete"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
Padding="0"
Margin="0"
IsEnabled="{Binding Converter={StaticResource inverseBoolConverter},
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type WO:OpCompTab}}, Path=DisableAll}"
Click="btnDelete_Click" Tag="{Binding Path=.}">
<Image Source="/Win7;component/Images/Icons/Remove.png"
Width="{StaticResource IconWidth}"
Height="{StaticResource IconHeight}" />
</Button>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
The listview gets populated by hooking an observable collection up to its ItemSource property. This generates a neat looking column of Delete buttons for each item in the observable collection.
But this presents a quandary: How do I access the "btnDelete" of an individual row of the ListView? I'd like to change its icon on a per-row basis. Is it just a matter of binding the observable collection to the cell template somehow?
Instead of hardcoding the Image.Source, bind it to a property in your row object. Another way is to create a value converter and pass in the row or some property if you can't or don't want to modify the row object to add an ImageSource property. Have the value converter return the correct image source based on the passed in property or some other logic.