Bind First ListView slected items to second ListView - c#

I have first and second ListView, as shown in the image:
I populated the first ListView, using this code
class CategoriesList
{
public string Category_Names { get; set; }
public double Category_Amount { get; set; }
public static List<CategoriesList> get_CategoryList()
{
try
{
SQLiteConnection con = new SQLiteConnection(" Data Source=system.sqlite; Version=3; Compress=True; ");
con.Open();
string query = " SELECT category_id, category_name, amount FROM acc_income_category WHERE deleted = 0 ORDER BY category_name ASC ";
SQLiteCommand cmd = new SQLiteCommand(query, con);
SQLiteDataReader dr = cmd.ExecuteReader();
var categories = new List<CategoriesList>();
while (dr.Read())
{
CategoriesList cl = new CategoriesList();
cl.Category_Names = dr.GetString(1);
cl.Category_Amount = dr.GetDouble(2);
categories.Add(cl);
}
con.Close();
return categories;
}
catch (Exception ex)
{
System.Windows.MessageBox.Show(ex.Message);
return null;
}
}
}
This is my Xaml Code
<ListView x:Name="ListBox_Category_Names" VerticalAlignment="Stretch" HorizontalAlignment="Left"
Width="auto" Height="300" SelectionMode="Single" Grid.Column="0" Margin="0,0,10,0"
ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto" SelectionChanged="ListBox_Category_Names_SelectionChanged"
>
<ListView.View>
<GridView>
<GridViewColumn Header="Category Name" DisplayMemberBinding="{Binding Category_Names}" Width="280" />
<GridViewColumn Header="Amount " DisplayMemberBinding="{Binding Category_Amount, ConverterCulture=ig-NG, StringFormat=\{0:C\}}" Width="130" />
</GridView>
</ListView.View>
</ListView>
<ListView x:Name="ListBox_Selected_Category" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
Width="auto" Height="300" SelectionMode="Single" Grid.Column="1" Margin="10,0,0,0"
ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto"
ItemsSource="{Binding SelectedItem, ElementName=ListBox_Category_Names}" >
<ListView.View>
<GridView>
<GridViewColumn Header="Category Name" DisplayMemberBinding="{Binding Category_Names}" Width="250" />
<GridViewColumn Header="Amount" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBox x:Name="txtBox_amount" Text="{Binding Category_Amount, ConverterCulture=ig-NG, StringFormat=\{0:C\}}" Width="200" Height="35" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
This is the Code thats Loads the First ListBox
ListBox_Category_Names.ItemsSource = CategoriesList.get_CategoryList();
Not MVVM
Now I'm stuck cause I need to bind the First ListView Selected Items to the Second ListView. Please, I really need help, been stuck with this for the past three (3) weeks. Thanks in advance.

You can do it in two ways: 1) code behind 2) mvvm
First way:handle the button click in the code behind:
public void Button_Click(object sender, EventArguments arg)
{
List<ListViewItem> mySelectedItems = new List<ListViewItem>();
foreach(ListViewItem item in myListView.SelectedItems)
{
mySelectedItems.Add(item);
}
}
Second way bind the multiple selection in the pattern of mvvm, for that look at:
Part 1
Part 2
Part 3

Related

How to pass a GridViewColumnHeader object to a method?

I have a listview that pulls a bunch of computer numbers and information from a database and displays it. I have a little menu that will filter this listview. Currently, clicking the columns sorts the listview by ascending/descending, but I want this function to be triggered by radio buttons.
I'm basically trying to trigger the GridViewColumnHeader_Click method from the radiobutton method. Here is the GridViewColumnHeader_Click method:
private GridViewColumnHeader listViewSortCol = null;
private SortAdorner listViewSortAdorner = null;
private void GridViewColumnHeader_Click(object sender, RoutedEventArgs e)
{
GridViewColumnHeader column = (sender as GridViewColumnHeader);
string sortBy = column.Tag.ToString();
if (listViewSortCol != null)
{
AdornerLayer.GetAdornerLayer(listViewSortCol).Remove(listViewSortAdorner);
lstView.Items.SortDescriptions.Clear();
}
ListSortDirection newDir = ListSortDirection.Ascending;
if (listViewSortCol == column && listViewSortAdorner.Direction == newDir)
newDir = ListSortDirection.Descending;
listViewSortCol = column;
listViewSortAdorner = new SortAdorner(listViewSortCol, newDir);
AdornerLayer.GetAdornerLayer(listViewSortCol).Add(listViewSortAdorner);
lstView.Items.SortDescriptions.Add(new SortDescription(sortBy, newDir));
}
private void RbLocation_Checked(object sender, RoutedEventArgs e)
{
GridViewColumnHeader_Click(sender, RoutedEventArgs e);
}
<RadioButton x:Name="rbP2L" Content="P2L" MinWidth="40" Checked="RbP2L_Checked"/>
<RadioButton x:Name="rbAssy" Content="Assembly" Checked="RbAssy_Checked"/>
<RadioButton x:Name="rbLocation" Content="Location" MinWidth="40" Checked="{Binding GridViewColumnHeader_Click}"/>
I tried to do the same thing with a binding, not not sure if that's the right way. I was getting a error when trying to do a binding:
System.Windows.Markup.XamlParseException: ''Provide value on 'System.Windows.Data.Binding' threw an exception.'
I think this doesn't work because I'm not binding it to anything, because it's an event.
The listview is defined as such:
<ListView Name="lstView" SelectionChanged="lstView_SelectionChanged_1" MouseDoubleClick="LstView_MouseDoubleClick" Grid.Column="0" Background="LightGray" Margin="10,10,0,10" Grid.RowSpan="3">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Width="Auto">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding PCID}"></TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
<GridViewColumn.Header>
<GridViewColumnHeader>
<TextBlock Text="PCID" HorizontalAlignment="Stretch"></TextBlock>
</GridViewColumnHeader>
</GridViewColumn.Header>
</GridViewColumn>
<GridViewColumn Width="Auto">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding ProductionArea}"></TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
<GridViewColumn.Header>
<GridViewColumnHeader Tag="ProductionArea" Click="GridViewColumnHeader_Click">
<TextBlock Text="ProductionArea"></TextBlock>
</GridViewColumnHeader>
</GridViewColumn.Header>
</GridViewColumn>
<GridViewColumn Width="Auto">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Type}"></TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
<GridViewColumn.Header>
<GridViewColumnHeader Tag="Type" Click="GridViewColumnHeader_Click">
<TextBlock Text="Type"></TextBlock>
</GridViewColumnHeader>
</GridViewColumn.Header>
</GridViewColumn>
<GridViewColumn Width="auto">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Location}"></TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
<GridViewColumn.Header>
<GridViewColumnHeader Tag="Location" Click="GridViewColumnHeader_Click">
<TextBlock Text="Location"></TextBlock>
</GridViewColumnHeader>
</GridViewColumn.Header>
</GridViewColumn>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
I figured I could use the tags to point to the header since everything has the same name, but I haven't been able to figure out the right wording. For example, how do I pass the Location header into the GridViewColumnHeader_Click method from outside of the click event? Thanks in advance, very stuck on this one.
To be honest, I don't understand what your problem is. In fact, you already have everything implemented.
Just in case, I'll show you an example.
using System;
using System.Collections.ObjectModel;
using System.Linq;
namespace Core2022.SO.AlexD.ManageGridViewColumn
{
public class SomeItem
{
public string Word { get; }
public int Value { get; }
public SomeItem(string word, int value)
{
Word = word;
Value = value;
}
private static ObservableCollection<SomeItem>? _itemsExample;
public static ObservableCollection<SomeItem> ItemsExample
{
get
{
if (_itemsExample is null)
{
Random random = new Random();
_itemsExample = new ObservableCollection<SomeItem>
(
"How to pass a GridViewColumnHeader object to a method?"
.Split()
.Select(word => new SomeItem(word, random.Next()))
);
}
return _itemsExample;
}
}
}
}
<Window x:Class="Core2022.SO.AlexD.ManageGridViewColumn.ManagerWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Core2022.SO.AlexD.ManageGridViewColumn"
xmlns:specialized="clr-namespace:System.Collections.Specialized;assembly=netstandard"
xmlns:sys="clr-namespace:System;assembly=netstandard"
xmlns:componentmodel="clr-namespace:System.ComponentModel;assembly=System.ComponentModel.TypeConverter"
mc:Ignorable="d"
Title="ManagerWindow" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<ListView x:Name="itemsView" Grid.Row="1"
ItemsSource="{x:Static local:SomeItem.ItemsExample}">
<ListView.View>
<GridView>
<GridViewColumn Header="Word">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Word}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Value">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Value}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
<UniformGrid Columns="2" Rows="2">
<TextBlock Text="SortDirection"/>
<TextBlock Text="Column"/>
<ComboBox x:Name="directionsView"
SelectedIndex="0"
SelectionChanged="OnDirectionChanged">
<ComboBox.ItemsSource>
<CompositeCollection>
<componentmodel:ListSortDirection>Ascending</componentmodel:ListSortDirection>
<componentmodel:ListSortDirection>Descending</componentmodel:ListSortDirection>
</CompositeCollection>
</ComboBox.ItemsSource>
</ComboBox>
<ComboBox x:Name="propertiesView"
SelectedIndex="0"
SelectionChanged="OnPropertyChanged">
<ComboBox.ItemsSource>
<specialized:StringCollection>
<sys:String>Un Sort</sys:String>
<sys:String>Word</sys:String>
<sys:String>Value</sys:String>
</specialized:StringCollection>
</ComboBox.ItemsSource>
</ComboBox>
</UniformGrid>
</Grid>
</Window>
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
namespace Core2022.SO.AlexD.ManageGridViewColumn
{
public partial class ManagerWindow : Window
{
public ManagerWindow()
{
InitializeComponent();
}
private string oldProperty = string.Empty;
private ListSortDirection oldDirection;
private void OnPropertyChanged(object sender, SelectionChangedEventArgs e)
{
string property = (string)propertiesView.SelectedItem;
itemsView.Items.SortDescriptions.Clear();
if (property is not nameof(SomeItem.Word) and not nameof(SomeItem.Value))
{
oldProperty = string.Empty;
directionsView.Visibility = Visibility.Hidden;
}
else if (property != oldProperty)
{
oldProperty = property;
directionsView.Visibility = Visibility.Visible;
oldDirection = ListSortDirection.Ascending;
directionsView.SelectedIndex = 0;
itemsView.Items.SortDescriptions.Add(new SortDescription(property, oldDirection));
}
}
private void OnDirectionChanged(object sender, SelectionChangedEventArgs e)
{
ListSortDirection direction = (ListSortDirection)directionsView.SelectedItem;
if (direction != oldDirection)
{
oldDirection = direction;
itemsView.Items.SortDescriptions.Clear();
itemsView.Items.SortDescriptions.Add(new SortDescription(oldProperty, direction));
}
}
}
}

How to get all checked selected items from Listview in c# WPF

I want to get all the items in a listview that the checkbox has checked.
<ListView x:Name="lvwStudent" IsSynchronizedWithCurrentItem="True" SelectionMode="Multiple" HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center">
<ListView.View>
<GridView>
<GridViewColumn Width="50">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox x:Name="cboxSelected" Content ="{Binding ID}" Width="20" Height="20" BorderBrush="#FF0C6161" HorizontalAlignment="Center" HorizontalContentAlignment="Center" Tag="{Binding ID}" IsChecked="{Binding IsChecked}" Checked="cboxSelected_Checked_1" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="NO." Width="53">
<GridViewColumn.CellTemplate>
<DataTemplate >
<Label Content ="{Binding ID}" FontSize="14" HorizontalContentAlignment="Center"></Label>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="STUDENT NAME" Width="auto">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Label Content ="{Binding STUDENT_NAME}" FontSize="14" HorizontalContentAlignment="Center"></Label>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
when I click the select button I want to get all selected ID and store in an array.
private void btnSelect_Click(object sender, RoutedEventArgs e)
{
int[] selectedId;
if(lvwMachine.SelectedItems.Count > 0)
{
foreach(..... )
{
//add all selected id in array selectedId
}
}
List<Student>StudentList = new Students().getStudent();
List<ListViewItem> ITEM = new List<ListViewItem>();
foreach (var s in StudentList)
{
ListViewItem OneItem = new ListViewItem();
OneItem.Content = new Student()
{ID = s.ID, STUDENT_NAME = s.name};
ITEM.Add(OneItem);
lvwMachine.ItemsSource = ITEM;
}
You can try this:
lvwMachine.ItemsSource.Where(element => element.IsChecked).ToArray();

Edit TextView column on ListView WPF

I'm Using WPF.
I have ListView with TextBox column and two checkboxs columns.
I want to edit the TextBox text by double click or something else.
What is the simple way to do that?
...
<GridViewColumn Header="Name" DisplayMemberBinding={Binding Path=fullName}" Width=500>
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBox Name="txtName"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
...
Here is a sample way of doing this...
public partial class MainWindow : Window
{
public List<string> Items { get; set; }
public MainWindow()
{
InitializeComponent();
Items = new List<string>();
LoadItems();
DataContext = this;
}
private void txtName_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
TextBox currentTextBox = (TextBox)sender;
if (currentTextBox.IsReadOnly)
currentTextBox.IsReadOnly = false;
else
currentTextBox.IsReadOnly = true;
}
private void LoadItems()
{
Items.Add("Coffee");
Items.Add("Sugar");
Items.Add("Cream");
}
}
<Grid>
<ListView ItemsSource="{Binding Items}">
<ListView.View>
<GridView>
<GridViewColumn Header="Name">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBox Name="txtName" Text="{Binding Mode=OneTime}" IsReadOnly="True" MouseDoubleClick="txtName_MouseDoubleClick" Width="100"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
Here is an example I have from an application that I wrote. The column JobName was to be user editable. This example allows the column to be editable and also gets rid of the border and lets the background blend into the row so it doesn't appear to have a text box in it.
Those can be edited out (BorderThickness="0" Background="Transparent").
My example binds to an MVVM ViewModel property called JobName and is set to be "TwoWay" so that changes to the view model will also reflect on the UI.
<ListView x:Name="lvJobs" HorizontalAlignment="Left" Height="628" Margin="30,62,0,0" ItemsSource="{Binding Jobs}"
SelectedItem="{Binding SelectedJob, Mode=TwoWay}" VerticalAlignment="Top" Width="335">
<ListView.View>
<GridView>
<GridViewColumn Header="Active" Width="50">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsActive, Mode=TwoWay}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Job Name" Width="150">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBox Text="{Binding JobName, Mode=TwoWay}" BorderThickness="0" Background="Transparent"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding User}" Header="User" Width="125"/>
</GridView>
</ListView.View>
</ListView>

Reading Data From WPF ListView. C#

How to read data from a WPF ListView?
Here is my code.
<ListView x:Name="LVR" AllowDrop="True" PreviewDrop="LVR_PreviewDrop" RenderTransformOrigin="0.505,0.506" Margin="0,0,0,0" Grid.Row="1" Grid.ColumnSpan="3" MouseEnter="LVR_MouseEnter" >
<ListView.View>
<GridView >
<GridViewColumn Header="Status" Width="40">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Image Source="index.png" Width="26"></Image>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="File Name">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding TBtxt}" FontWeight="Bold" Foreground="Blue" Cursor="Hand" Height="30" TextAlignment="Left" HorizontalAlignment="Center"></TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
And i am inserting items to the List view like this.
void Insert()
{
WinForms.OpenFileDialog ofd = new WinForms.OpenFileDialog();
ofd.Multiselect = true;
ofd.Title = "Select .TXT File";
ofd.FileName = "";
ofd.Filter = "TXT | *.txt";
if (ofd.ShowDialog() == WinForms.DialogResult.OK)
{
foreach (var filename in ofd.FileNames)
{
if (System.IO.Path.GetExtension(filename).ToUpperInvariant() == ".txt")
{
LVR.Items.Add(new StackItems { TBtxt = filename });
}
}
}
}
class StackItems
{
public string TBtxt { get; set; }
public Image imgg { get; set; }
}
Once I completed adding files, my ListView will looks like this.
|Status | File Name|
|[Image]| test.txt |
|[Image]| test1.txt|
(Sorry. I don't have enough reputation to post image)
Now how will I read the 'File Name' from second column?
I am very new to WPF.
Thanks in advance.
In short, you should be data binding a collection of items (one for each row) to the ListView.ItemsSource property:
<ListView ItemsSource="{Binding SomeCollection}">
<ListView.View>
<!-- Define your view here -->
</ListView.View>
</ListView>
If you do this, then accessing the items is as simple as this (using Linq):
var firstItem = SomeCollection.First();
An improvement on this situation would be to data bind another property of the same type as the objects on the data bound collection to the ListView.SelectedItem property:
<ListView ItemsSource="{Binding SomeCollection}" SelectedItem="{Binding CurrentItem}">
<ListView.View>
<!-- Define your view here -->
</ListView.View>
</ListView>
Doing this will enable you to access properties from the currently selected item from the ListView like this:
int someValue = CurrentItem.SomeProperty;
Please refer to the ListView Class page on MSDN for further help.

WPF - Filling a ListView

I have a 2 column ListView and I'm trying to fill it using and IDictionary with the following code.
System.Collections.IDictionary entryList = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User);
foreach (System.Collections.DictionaryEntry de in entryList)
{
Row row = new Row();
row.Name1 = (string)de.Key;
row.Name2 = (string)de.Value;
this.list1.Items.Add(row);
}
public class Row
{
public string Name1 { get; set; }
public string Name2 { get; set; }
}
XAML:
<ListView x:Name="varList"
Grid.ColumnSpan="1"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Height="400"
Width="500"
Margin="0, 30, 0, 0">
<ListView.View>
<GridView>
<GridViewColumn Width="150" Header="Name" />
<GridViewColumn Width="350" Header="Path" />
</GridView>
</ListView.View>
</ListView>
But every row and column gets filled with "Project.Views.Row".
Anyone got any idea on how to fix it? Thank you very much.
A ListView (and every other control for that matter) will display the results of calling ToString when given an object to display.
For a standard class, thats its qualified name; Project.Views.Row in your example.
There are two ways to fix this:
Don't add an object. Instead, format the string as you want it ie:
list1.Items.Add(String.Format({0}:{1}, row.Name1, row.Name2));
Do this the right way and use MVVM. In this case your XAML needs a data template:
<ListView ItemsSource="{Binding Rows}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name1}"/>
<TextBlock Text="{Binding Name2}"/>
</StackPanel>
</DataTemplate>
<ListView.ItemTemplate>
</ListView>
For a grid view:
<ListView.View>
<GridView>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name1}" />
<GridViewColumn Header="Path" DisplayMemberBinding="{Binding Name2}"/>
</GridView>
</ListView.View>
Binding the ItemsSource is not actually necessary, but since we are doing everything the right way, you should do it so you are not directly manipulating the UI from code.

Categories