WPF - Different SelectedValues in different GridViewColumns? - wpf

I have 12 Properties and I want to bind each of them to one GridViewColumn in a ListView. They contain an ID (string) and look like the following:
//DAR01
public static readonly PropertyInfo<string> DAR01Property = RegisterProperty<string>(p => p.DAR01);
/// <summary>
///Date type
/// </summary>
public string DAR01
{
get { return GetProperty( DAR01Property); }
set { SetProperty(DAR01Property, value); }
}
I also have a Key-Table in my database which contains a key and a description, which I already have in my Code-Behind:
public System.Collections.Generic.IEnumerable<AOK.NW.Beihilfe.Customizing.Schluessel> PlanungsdatenSchluessel
{
get
{
System.Collections.Generic.IEnumerable<AOK.NW.Beihilfe.Customizing.Schluessel> SchluessellistePlanungsdaten = Schluesselliste.GetSchluesselliste().Where<Schluessel>(x => x.Gruppe == "T548T");
return SchluessellistePlanungsdaten;
}
}
Basically the easiest way to explain what I want are these following ComboBoxes, but in a GridView with multiple GridViewColumns which have different Bindings:
<ComboBox Grid.Row="2" Grid.Column="1" Width="Auto"
ItemsSource="{Binding Path=PlanungsdatenSchluessel}"
DisplayMemberPath="Beschreibung"
SelectedValuePath="Id"
SelectedValue="{Binding Path=CurrentDate.DAR01}"
IsEnabled="{Binding Path=IsBearbeiten}"/>
<ComboBox Grid.Row="3" Grid.Column="1" Width="Auto"
ItemsSource="{Binding Path=PlanungsdatenSchluessel}"
DisplayMemberPath="Beschreibung"
SelectedValuePath="Id"
SelectedValue="{Binding Path=CurrentDate.DAR02}"
IsEnabled="{Binding Path=IsBearbeiten}"/>
[...]
My GridViewColumns (goes up to DAR12):
<ListView Grid.Row="0"
ItemsSource="{Binding Path=Person.Planungsdaten}"
IsSynchronizedWithCurrentItem="True"
SelectedItem="{Binding SelectedItem}"
MaxHeight="580" Height="Auto"
Width="Auto"
ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Auto">
<GridViewColumn Width="Auto" DisplayMemberBinding="{Binding Path=DAR01}">
<GridViewColumnHeader Name="DAR01" Content="Datentyp 01"/>
</GridViewColumn>
<GridViewColumn Width="Auto" DisplayMemberBinding="{Binding Path=DAR02}">
<GridViewColumnHeader Name="DAR02" Content="Datentyp 02"/>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Any ideas how I can achieve that? I am grateful for any tip!

Related

Loop through the second column of WPF ListView and retrieve value of ComboBox in each row

I have a two-column ListView with CheckBoxes in the first column and ComboBoxes in the second column. I need to loop through the ComoboBoxes in the second column and retrieve the selected values (or indexes) from each ComboBox, along with some index or identifier of the ComboBox, and put the values in an array. For example, the layout looks like this:
COLUMN 1 COLUMN 2
======== ========
ChBx 1 Combo1
ChBx 2 Combo2
I need to grab the SelectedValue or SelectedIndex of each ComboBox in the second column and put it into an array in the right order. But, what I've found on the internet is to use: myListView.Items(0).SubItems(1).Text, to loop through the second column. However, my second column contains a ComboBox and I want its' value (not some Text property). Any ideas? My XAML markup is below.
<ListView IsSynchronizedWithCurrentItem="True" Margin="0,0,10,10" Name="patternList" Height="139" VerticalAlignment="Bottom" HorizontalAlignment="Right" Width="112" BorderBrush="{x:Null}" BorderThickness="1" Background="White" >
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="Pattern">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox Content="{Binding outContent}"
ToolTip="{Binding outToolTip}"
IsThreeState="False"
IsChecked="{Binding Path=outIsChecked, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Freq" Width="55">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ComboBox HorizontalContentAlignment="Center"
Height="14"
Padding="0"
SelectionChanged="FrequencyChanged_OnSelectionChanged"
FontSize="10">
<ComboBoxItem Content="0%"/>
<ComboBoxItem Content="10%"/>
<ComboBoxItem Content="20%"/>
<ComboBoxItem Content="30%"/>
<ComboBoxItem Content="40%"/>
<ComboBoxItem Content="50%"/>
<ComboBoxItem Content="60%"/>
<ComboBoxItem Content="70%"/>
<ComboBoxItem Content="80%"/>
<ComboBoxItem Content="90%"/>
<ComboBoxItem Content="100%"/>
</ComboBox>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
Bind SelectedValue to a property in your ViewModel. And in the Setter of that property, also update the collection.
Second approach, in your FrequencyChanged_OnSelectionChanged event handler. You can keep updating your collection there too.
From my perspective it would be better to generate items for the combobox in list item viewmodel, and bind to selected item in that view model. Below is the code that illustrates the approach.
XAML
<Window x:Class="ComboboxesInGrid.MainWindow"
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:ComboboxesInGrid"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<ListView IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding ListItems}" Margin="0,0,10,10" Name="patternList" BorderBrush="{x:Null}" BorderThickness="1" Background="White" >
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="Pattern" Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox Content="{Binding outContent}"
ToolTip="{Binding outToolTip}"
IsThreeState="False"
IsChecked="{Binding Path=outIsChecked, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Freq" Width="155">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ComboBox HorizontalContentAlignment="Center"
Height="14"
Padding="0"
SelectedItem="{Binding outComboSelected}"
ItemsSource="{Binding outComboValues}"
FontSize="10">
</ComboBox>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
<TextBlock Grid.Row="1" Text="{Binding SelectedComboItems}" />
</Grid>
</Window>
C#
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
namespace ComboboxesInGrid
{
public class MainWindowViewModel : ViewModelBase
{
private ObservableCollection<ListItemViewModel> _listItems = new ObservableCollection<ListItemViewModel>();
public string SelectedComboItems
{
get { return String.Join(",", _listItems.Select(li => $"{li.outContent}-{li.outIsChecked}-{li.outComboSelected}")); }
}
public ObservableCollection<ListItemViewModel> ListItems
{
get { return _listItems; }
set { _listItems = value; OnProperyChanged(); }
}
public MainWindowViewModel()
{
AddListItem(new ListItemViewModel() { outContent = "ChBx 1 ", outToolTip="Tooooool", outIsChecked = false, outComboSelected="30%" });
AddListItem(new ListItemViewModel() { outContent = "ChBx 2 ", outComboSelected = "70%" });
}
private void AddListItem(ListItemViewModel item)
{
item.PropertyChanged += (s, e) => OnProperyChanged(nameof(SelectedComboItems));
_listItems.Add(item);
}
}
public class ListItemViewModel : ViewModelBase
{
private string _outContent;
public string outContent
{
get { return _outContent; }
set { _outContent = value; OnProperyChanged(); }
}
private string _outToolTip;
public string outToolTip
{
get { return _outToolTip; }
set { _outToolTip = value; OnProperyChanged(); }
}
private bool? _outIsChecked;
public bool? outIsChecked
{
get { return _outIsChecked; }
set { _outIsChecked = value; OnProperyChanged(); }
}
private string _outComboSelected;
public string outComboSelected
{
get { return _outComboSelected; }
set { _outComboSelected = value; OnProperyChanged(); }
}
public IEnumerable<string> outComboValues
{
get
{
return Enumerable.Range(0, 11).Select(i => $"{i*10}%");
}
}
}
public class ViewModelBase : INotifyPropertyChanged
{
protected void OnProperyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
}

How to set SelectedItem in listview control?

I have UserControl(AllCustomerView) in project and its Viewmodel as ALlCustomerViewModel consists a property as SearchText.
SearchText is selected value for TextBox inside a listview in UserControl.
SearchItem is set as customerViewmdel for SearchText.
But in listview , SearchItem is not set as selected
in AllCustomerView.xaml
<TextBlock>
<TextBox
Width="150"
Text="{Binding Path=SearchText, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">
</TextBox>
<Button
Command="{Binding Path=SearchCommand}"
Content=" Search ">
</Button>
</TextBlock>
<ListView
SelectedValue="{Binding Path=SearchText}"
ItemsSource="{Binding Path=AllCustomers}"
FontFamily="Tahoma"
FontSize="14"
ItemContainerStyle="{StaticResource CustomerItemStyle}"
IsSynchronizedWithCurrentItem="True">
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button
Command="{Binding ElementName=Root, Path=DataContext.DeleteCommand}"
Content="x"
FontFamily="Tahoma"
FontSize="10"
/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button
FontFamily="Tahoma"
FontSize="10"
Content="Edit"
Command="{Binding Path=DataContext.Editcommand,ElementName=Root}"
/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn
Header="CustomerID"
Width="130"
DisplayMemberBinding="{Binding Path=CustomerID}"/>
<GridViewColumn
Header="Contact Name"
Width="130"
DisplayMemberBinding="{Binding Path=ContactName}"/>
<GridViewColumn
Header="Company Name"
Width="130"
DisplayMemberBinding="{Binding Path=CompanyName}"/>
<GridViewColumn
Width="130"
Header="Contact Name"
DisplayMemberBinding="{Binding Path=ContactTitle}"
/>
</GridView>
</ListView.View>
</ListView>
and its viewmodel(AllcustomerViewModel.cs)
public ICommand SearchCommand
{
get
{
if (_search == null)
_search = new Relaycommand(SearchCustomer);
return _search;
}
}
public void SearchCustomer(object o)
{
System.Windows.Forms.MessageBox.Show(SearchItem.ToString());
}
public string searchText;
public string SearchText
{
get { return searchText; }
set
{
searchText = value;
var customerExsits = AllCustomers.Where(q => q.CustomerID.Trim().Equals(searchText));
if (customerExsits.Any())
{
SearchItem = customerExsits.Single();
}
}
}
public CustomerViewModel SearchItem
{
get;
set;
}
what should i set in SelectedValue in ListView, whether to set Customerviewmodel(as SelectedItem) or to set CustomerID(as SearchText)?
You should do the following:
Use this binding in your ListView: SelectedItem="{Binding Path=SearchItem }". Don't use SelectedValue.
Implement INotifyPropertyChanged in your ViewModel and raise the PropertyChanged event in the setter of the SearchItem property. Obviously, you need to change this property from an automatic one to a classical one with a backing field:
public CustomerViewModel SearchItem
{
get { return _searchItem; }
set
{
if(value == _searchItem)
return;
_searchItem = value;
RaisePropertyChanged("SearchItem");
}
}

WPF ListView binding to a custom class

My question is pretty much simple as it looks. But the way I am trying to implement it is a little complex. I have implemented a Singleton pattern in order to use some global data I have class Contact History, I want to bind some of its properties to the ListView->GridView->GridViewColumn. I have a list that I want to bind. I have gone through some tutorials and tried to implement them but it seems that there are some issues with my XAML code because when I bind the listobject it can resolve its path. It seems that I am not including something right. Following is the code that would be required
Singleton Class
class Singleton
{
private static Singleton instance = new Singleton();
public List<Contacts> ContactList ;
public SQLiteConnectionStringBuilder builder;
public SqLiteProvider _db;
public DataHelper _helper;
public DataTable DataTable_Contacts;
public DataTable DataTable_ContactHistory;
public List<String> Contact_Names;
public ListBox ListBox_names;
public int Contact_Index;
public int ContactHistory_Index;
private Singleton()
{
ContactList = new List<Contacts>();
builder = new SQLiteConnectionStringBuilder();
builder.DataSource = Util.GetCurrentDirectory() + "TestDatabases\\DatabaseAccessLayerSqlLite.db";
_db = new SqLiteProvider();
_db.ConnectionString = builder.ConnectionString;
_helper = new DataHelper(_db);
DataTable_Contacts = new DataTable();
DataTable_ContactHistory = new DataTable();
Contact_Names = new List<string>();
}
.
.
}
Xaml Code
<Window x:Class="NET_Data_Access_Layer_Demo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:themes="clr-namespace:WPF.Themes;assembly=WPF.Themes"
xmlns="clr-namespace:NET_Data_Access_Layer_Demo.Properties"
Title="Customer Contact Manager" Height="535" Width="702" Loaded="Window_Loaded" Activated="Window_Activated">
<GroupBox Header="History" Height="230" HorizontalAlignment="Left" Margin="182,252,0,0" Name="groupBox_history" VerticalAlignment="Top" Width="487">
<Grid>
<Button Content="Edit" Height="23" HorizontalAlignment="Left" Margin="164,163,0,0" Name="button_edithistory" VerticalAlignment="Top" Width="75" Click="button_edithistory_Click" IsEnabled="False" />
<Button Content="Delete" Height="23" HorizontalAlignment="Left" Margin="269,163,0,0" Name="button_deletehistory" VerticalAlignment="Top" Width="75" IsEnabled="False" Click="button_deletehistory_Click" />
<Button Height="23" HorizontalAlignment="Left" Margin="62,163,0,0" Name="button_addhistory" VerticalAlignment="Top" Width="75" Click="button_addhistory_Click" Content="Add" IsEnabled="False" />
<ListView IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding ContactHistoryList}" Height="129" HorizontalAlignment="Left" Margin="33,19,0,0" Name="listView_history" VerticalAlignment="Top" Width="419">
<ListView.View>
<GridView>
<GridViewColumn Header="Date" Width="80" DisplayMemberBinding="{Binding ContactHistory_Date}" />
<GridViewColumn Header="Type" Width="80" DisplayMemberBinding="{Binding ContactHistory_Type}" />
<GridViewColumn Header="Note" Width="300" DisplayMemberBinding="{Binding ContactHistory_Note}" />
</GridView>
</ListView.View>
</ListView>
</Grid>
</GroupBox>
.
.
.
</window>
I am assinging the datacontext properly, but its my hunch that the xaml can't understand all the binding references that I provided I might be missing some custom class reference or something like that. I would be obliged if anyone can help me in this regard
Regards
Umair
(Where are you assigning the datacontext? What are you assigning it to? )
There is no property anywhere in your code called ContactHistoryList. That means your item source can't be binding correctly, to begin with, unless there's something involved in the data context that you're not explaining.
Also, it's not possible to bind to public fields using WPF. You need to wrap your fields in public properties and bind to those instead.
Delete binding param from listview.
Assign listview.itemssource by code.
otherwise
Add ObjectCollection to resources with x:Key="ContactHistoryList"
bye tiz
try this:
<ListView IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding ContactHistoryList}"
Height="129" HorizontalAlignment="Left" Margin="33,19,0,0" Name="listView_history" VerticalAlignment="Top" Width="419">
<ListView.ItemTemplate>
<DataTemplate>
<ListViewItem>
<GridView>
<GridViewColumn Header="Date" Width="80" DisplayMemberBinding="{Binding ContactHistory_Date}" />
<GridViewColumn Header="Type" Width="80" DisplayMemberBinding="{Binding ContactHistory_Type}" />
<GridViewColumn Header="Note" Width="300" DisplayMemberBinding="{Binding ContactHistory_Note}" />
</GridView>
</ListViewItem>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

WPF - Listview with button

i have a listview template and one column is a button. I need selected item when i click in this button. How i can do this ??
To cature the selected ListView item inside a button pressed event you can leverage the MVVM pattern. In my ListView, in the XAML, I bind the ItemsSource and SelectedItem to a ViewModel class. I also bind my button Command in the template to RunCommand in the ViewModel.
The tricky part is getting the binding correct from the template to the active DataContext.
Once you do this you can capture the SelectedCustomer inside the RunCommand that
gets executed when the button gets pressed.
I've included some of the code to help get you started.
You can find implementations of ViewModelBase and DelegateCommand via Google.
Here is the XAML:
<Window x:Class="ListViewScrollPosition.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Main Window" Height="400" Width="400">
<Grid>
<ListView ItemsSource="{Binding Path=Customers}"
SelectedItem="{Binding Path=SelectedCustomer}"
Width="Auto">
<ListView.View>
<GridView>
<GridViewColumn Header="First Name">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Margin="6,2,6,2">
<TextBlock Text="{Binding FirstName}"/>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Last Name">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Margin="6,2,6,2">
<TextBlock Text="{Binding LastName}"/>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Address">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Margin="6,2,6,2">
<Button Content="Address"
Command="{Binding
Path=DataContext.RunCommand,
RelativeSource=
{RelativeSource FindAncestor,
AncestorType={x:Type ItemsControl}}}"/>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>
Here is the ViewModel:
using System.Collections.ObjectModel;
using System.Windows.Input;
using ListViewScrollPosition.Commands;
using ListViewScrollPosition.Models;
namespace ListViewScrollPosition.ViewModels
{
public class MainViewModel : ViewModelBase
{
public ICommand RunCommand { get; private set; }
public MainViewModel()
{
RunCommand = new DelegateCommand<object>(OnRunCommand, CanRunCommand);
_customers = Customer.GetSampleCustomerList();
_selectedCustomer = _customers[0];
}
private ObservableCollection<Customer> _customers =
new ObservableCollection<Customer>();
public ObservableCollection<Customer> Customers
{
get
{
return _customers;
}
}
private Customer _selectedCustomer;
public Customer SelectedCustomer
{
get
{
return _selectedCustomer;
}
set
{
_selectedCustomer = value;
OnPropertyChanged("SelectedCustomer");
}
}
private void OnRunCommand(object obj)
{
// use the SelectedCustomer object here...
}
private bool CanRunCommand(object obj)
{
return true;
}
}
}
Here is where I link in the ViewModel to the View:
public partial class MainView : Window
{
public MainView()
{
InitializeComponent();
DataContext = new ViewModels.MainViewModel();
}
}
Example with a regular click event in the code behind:
<ListView Height="167.96" VerticalAlignment="Top" ItemsSource="{Binding FulfillmentSchedules}" SelectedItem="{Binding SelectedFulfillmentSchedule}">
<ListView.View>
<GridView>
<GridViewColumn Header="Request">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0}-{1}-{2}">
<Binding Path="Template.ProjectNumber" />
<Binding Path="Template.JobNumber" />
<Binding Path="Template.RequestId" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Template" DisplayMemberBinding="{Binding Template.Name}"/>
<GridViewColumn Header="Start Date" DisplayMemberBinding="{Binding StartDate}"/>
<GridViewColumn Header="Records" DisplayMemberBinding="{Binding Parameters.Records}"/>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button Name="BtnYourButton" Content="Your Button" Click="BtnYourButton_Click" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Code behind:
private void BtnYourButton_Click(object sender, RoutedEventArgs e)
{
var boundData= (YourBoundDataType)((Button)sender).DataContext;
//do what you need to do here, including calling other methods on your VM
}
Note: While I certainly appreciate MVVM, I've come to accept that there is a pretty steep slope of dimminishing returns once you cross into actions and messaging between the form and the VM, so I use it only in cases of complex relationships between VMs or large singular VMs. For CRUD style data-centric applications I prefer to handle actions and message relay with the code behind.

Listview of items from a object selected in another listview

Ok the title maybe a little confusing. I have a database with the table Companies wich has one-to-many relotionship with another table Divisions ( so each company can have many divisions ) and division will have many employees.
I have a ListView of the companies. What I wan't is that when I choose a company from the ListView another ListView of divisions within that company appears below it. Then I pick a division and another listview of employees within that division appaers below that. You get the picture.
Is there anyway to do this mostly inside the XAML code declaritively (sp?). I'm using linq so the Company entity objects have a property named Division wich if I understand linq correctly should include Division objects of the divisions connected to the company. So after getting all the companies and putting them as a itemsource to CompanyListView this is where I currently am.
<ListView x:Name="CompanyListView"
DisplayMemberPath="CompanyName"
Grid.Row="0" Grid.Column="0" />
<ListView DataContext="{Binding ElementName=CompanyListView, Path=SelectedItem}"
DisplayMemberPath="Division.DivisionName"
Grid.Row="1" Grid.Column="0" />
I know I'm way off but I was hoping by putting something specific in the DataContext and DisplayMemberPath I could get this to work. If not then I have to capture the Id of the company I guess and capture a select event or something.
Another issue but related is the in the seconde column besides the lisview I wan't to have a details/edit view for the selected item. So when only a company is selected details about that will appear then when a division under the company is picked It will go there instead, any ideas?
You can use the MVVM pattern to bind your XAML to a class that contains information for your ListViews and reset the content for the Division collection based on the selected Comany item.
Here is a basic sample to get you started.
Here are two ListView controls in XAML:
<Window x:Class="MultiListView.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Main Window" Height="400" Width="800">
<DockPanel>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<ListView Grid.Row="0"
ItemsSource="{Binding Companies}"
SelectedItem="{Binding Company, Mode=TwoWay}">
<ListView.View>
<GridView>
<GridViewColumn Header="Name"
DisplayMemberBinding="{Binding CompanyName}" />
<GridViewColumn Header="Description"
DisplayMemberBinding="{Binding Description}" />
</GridView>
</ListView.View>
</ListView>
<ListView Grid.Row="1"
ItemsSource="{Binding Divisions}"
SelectedItem="{Binding Division, Mode=TwoWay}">
<ListView.View>
<GridView>
<GridViewColumn Header="Name"
DisplayMemberBinding="{Binding DivisionName}" />
<GridViewColumn Header="Description"
DisplayMemberBinding="{Binding Description}" />
</GridView>
</ListView.View>
</ListView>
</Grid>
</DockPanel>
</Window>
In the code-behind set the DataContext for the Window to a class the contains the binding references used in the XAML.
public partial class MainView : Window
{
MainViewModel _mvm = new MainViewModel();
public MainView()
{
InitializeComponent();
DataContext = _mvm;
}
}
The following class uses the MVVM pattern, which you can find lots of information
on in StackOverFlow. This class contains the data that the XAML binds with. Here
is where you can use LINQ to load/reload the collections.
using System.Collections.ObjectModel;
using MultiListView.Models;
namespace MultiListView.ViewModels
{
public class MainViewModel : ViewModelBase
{
public MainViewModel()
{
_companies = new ObservableCollection<Company>();
_companies.Add(new Company("Stackoverflow", "QA web site"));
_companies.Add(new Company("Fog Creek", "Agile Bug Tracking"));
_companies.Add(new Company("Second Beach", "Not sure yet"));
_divisions = new ObservableCollection<Division>();
}
private ObservableCollection<Company> _companies;
public ObservableCollection<Company> Companies
{
get { return _companies; }
set
{
_companies = value;
OnPropertyChanged("Companies");
}
}
private Company _company;
public Company Company
{
get { return _company; }
set
{
_company = value;
// load/reload divisions for the selected company here
LoadDivisions();
OnPropertyChanged("Company");
}
}
// hack to keep the example simpe...
private void LoadDivisions()
{
_divisions.Clear();
// use db or linq here to filiter property
if ( _company != null )
{
if ( _company.CompanyName.Equals("Stackoverflow") )
{
_divisions.Add( new Division("QA", "Test all day"));
_divisions.Add( new Division("Write", "Doc all day"));
_divisions.Add( new Division("Code", "Code all day"));
}
else if (_company.CompanyName.Equals("Fog Creek"))
{
_divisions.Add(new Division("Test", "Test all day"));
_divisions.Add(new Division("Doc", "Doc all day"));
_divisions.Add(new Division("Develop", "Code all day"));
}
else if (_company.CompanyName.Equals("Second Beach"))
{
_divisions.Add(new Division("Engineering", "Code all day"));
}
}
}
private ObservableCollection<Division> _divisions;
public ObservableCollection<Division> Divisions
{
get { return _divisions; }
set
{
_divisions = value;
OnPropertyChanged("Divisions");
}
}
private Division _division;
public Division Division
{
get { return _division; }
set
{
_division = value;
OnPropertyChanged("Division");
}
}
}
}
OnPropertyChanged implements INotifyPropertyChanged.
When the properties of a ViewModel change, the Views bound to the ViewModel receive a notification when the ViewModel raises its PropertyChanged event.
You can find examples in most MVVM libraries, or look to MSDN for an example.
If Divisions is a property of Company, you could probably do something like this:
<Window x:Class="MultiListView.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Main Window" Height="400" Width="800">
<DockPanel>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<ListView Grid.Row="0"
x:Name="lvCompanies"
ItemsSource="{Binding Companies}"
SelectedItem="{Binding Company, Mode=TwoWay}">
<ListView.View>
<GridView>
<GridViewColumn Header="Name"
DisplayMemberBinding="{Binding CompanyName}" />
<GridViewColumn Header="Description"
DisplayMemberBinding="{Binding Description}" />
</GridView>
</ListView.View>
</ListView>
<ListView Grid.Row="1"
ItemsSource="{Binding ElementName='lvCompanies', Path=SelectedItem.Divisions}"
SelectedItem="{Binding Division, Mode=TwoWay}">
<ListView.View>
<GridView>
<GridViewColumn Header="Name"
DisplayMemberBinding="{Binding DivisionName}" />
<GridViewColumn Header="Description"
DisplayMemberBinding="{Binding Description}" />
</GridView>
</ListView.View>
</ListView>
</Grid>
</DockPanel>
</Window>

Resources