WPF ListView binding to a custom class - wpf

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>

Related

WPF - Different SelectedValues in different GridViewColumns?

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!

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>

WPF - How to center column data in ListView?

I'm still learning WPF, but I'm really confused about something that should be really simple. What I want to do is to center the contents of the 3rd and 4th columns. When I run this, the columns are left justified:
<ListView Margin="0" x:Name="listMonitoredUrls" AlternationCount="1"
ItemsSource="{Binding}" >
<ListView.View>
<GridView>
<GridViewColumn Header="Description" DisplayMemberBinding="{Binding FriendlyDesc}"/>
<GridViewColumn Header="Url" DisplayMemberBinding="{Binding Url}"/>
<GridViewColumn Header="Frequency">
<GridViewColumn.CellTemplate >
<DataTemplate>
<TextBlock Text="{Binding ScanFrequencyMinutes}"
HorizontalAlignment="Center"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Next Scan" >
<GridViewColumn.CellTemplate >
<DataTemplate>
<TextBlock Text="{Binding TimeNextScanStr}"
HorizontalAlignment="Center"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
I"m really starting to like WPF, but some simple things like this seem to be really hard.
Try using the TextAlignment property instead of HorizontalAlignment - should do it.
To my understanding HorizontalAlignment="Center" will center your textblock not the text in it.
This might be a long shot but i've had to do it for listboxes where the items are defined by templates. Try setting the HorizontalContentAlignment="Stretch" on your ListView. If I don't set that the items take only as much space as they need and are left justified.
I've created a solution which works under the common scenario of:
<GridViewColumn Header="Some Property" DisplayMemberBinding="{Binding SomeProperty}" />
where one only wants a simple DisplayMemberBinding with text without having to specify a CellTemplate
the new code uses an attached property and becomes:
<GridViewColumn Header="Some Property" DisplayMemberBinding="{Binding SomeProperty}"
ctrl:GridViewExtensions.IsContentCentered="True" />
attached property code:
public static class GridViewExtensions
{
#region IsContentCentered
[Category("Common")]
[AttachedPropertyBrowsableForType(typeof(GridViewColumn))]
public static bool GetIsContentCentered(GridViewColumn gridViewColumn)
{
return (bool)gridViewColumn.GetValue(IsContentCenteredProperty);
}
public static void SetIsContentCentered(GridViewColumn gridViewColumn, bool value)
{
gridViewColumn.SetValue(IsContentCenteredProperty, value);
}
public static readonly DependencyProperty IsContentCenteredProperty =
DependencyProperty.RegisterAttached(
"IsContentCentered",
typeof(bool), // type
typeof(GridViewExtensions), // containing type
new PropertyMetadata(default(bool), OnIsContentCenteredChanged)
);
private static void OnIsContentCenteredChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
OnIsContentCenteredChanged((GridViewColumn)d, (bool)e.NewValue);
}
private static void OnIsContentCenteredChanged(GridViewColumn gridViewColumn, bool isContentCentered)
{
if (isContentCentered == false) { return; }
// must wait a bit otherwise GridViewColumn.DisplayMemberBinding will not yet be initialized,
new DispatcherTimer(TimeSpan.FromMilliseconds(100), DispatcherPriority.Normal, OnColumnLoaded, gridViewColumn.Dispatcher)
{
Tag = gridViewColumn
}.Start();
}
static void OnColumnLoaded(object sender, EventArgs e)
{
var timer = (DispatcherTimer)sender;
timer.Stop();
var gridViewColumn = (GridViewColumn)timer.Tag;
if (gridViewColumn.DisplayMemberBinding == null)
{
throw new Exception("Only allowed with DisplayMemberBinding.");
}
var textBlockFactory = new FrameworkElementFactory(typeof(TextBlock));
textBlockFactory.SetBinding(TextBlock.TextProperty, gridViewColumn.DisplayMemberBinding);
textBlockFactory.SetValue(TextBlock.TextAlignmentProperty, TextAlignment.Center);
var cellTemplate = new DataTemplate { VisualTree = textBlockFactory };
gridViewColumn.DisplayMemberBinding = null; // must null, otherwise CellTemplate won't be recognized
gridViewColumn.CellTemplate = cellTemplate;
}
#endregion IsContentCentered
}
Here is my example to show a working xaml:
<Window x:Class="WPF_Tutorial.Rich_text_controls.BlockUIContainerCenteredColumnSample"
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"
mc:Ignorable="d"
xmlns:self="clr-namespace:WPF_Tutorial.Rich_text_controls"
Title="BlockUIContainerCenteredColumnSample" Height="275" Width="300"
WindowStartupLocation="CenterScreen">
<Window.Resources>
<x:Array x:Key="UserArray" Type="{x:Type self:User}">
<self:User Name="John Doe" Age="42" />
<self:User Name="Jane May-Anne Josephine Renalds Doe" Age="36" />
</x:Array>
</Window.Resources>
<Grid>
<FlowDocumentScrollViewer>
<FlowDocument>
<Paragraph FontSize="36" Margin="0">Users</Paragraph>
<Paragraph FontStyle="Italic" TextAlignment="Left" FontSize="14" Foreground="Gray">Here's a list of our users, inside our FlowDocument, in a completely interactive ListView control!</Paragraph>
<BlockUIContainer>
<ListView BorderThickness="0" ItemsSource="{StaticResource UserArray}" HorizontalAlignment="Center">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<!-- This stretches out the TextBlock width to the column width -->
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" Width="150" />
<GridViewColumn>
<GridViewColumnHeader Content="Age" Width="75" />
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Age}" TextAlignment="Center" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</BlockUIContainer>
<Paragraph FontStyle="Italic" TextAlignment="Left" FontSize="14" Foreground="Gray">More content can go here...</Paragraph>
</FlowDocument>
</FlowDocumentScrollViewer>
</Grid>
</Window>
Notice the <ListView.ItemContainerStyle> block. It has the <Setter ....
Without this, as per AndyG's text, nothing will work the way you want.
This has been very frustrating trying to work out.
By the way, here is the backing-code for this xaml:
namespace WPF_Tutorial.Rich_text_controls
{
using System.Windows;
public partial class BlockUIContainerCenteredColumnSample : Window
{
public BlockUIContainerCenteredColumnSample()
{
InitializeComponent();
}
}
public class User
{
public int Age { get; set; }
public string Name { get; set; }
}
}
What you should see when run

Binding a wpf listview to a Dataset....Possible..?

I was struggling moving to Wpf,I am just stuck while trying out databinding to a lsitview.I want to databind a listview to a dataset(dataset because the data i want to display in columns belongs to different tables).I am attaching a sample code that i am trying with.It works alright but the listliew only shows one row.What could be wrong.Can anyone guide me through.All the samples available are using datatables.None specifies about binding to a dataset.Pls help..any input will be highly appreciated...thanks in advance
My Xaml
<Grid>
<TextBox Text="" Height="20" Width="100" HorizontalAlignment="Left" Margin="15,13,0,0" VerticalAlignment="Top"></TextBox>
<TextBox Text="" Height="20" Width="100" HorizontalAlignment="Left" Margin="15,42,0,0" VerticalAlignment="Top"></TextBox>
<ListView Margin="15,89,63,73" Name="lst" ItemsSource="{Binding}">
<ListView.View>
<GridView>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Path=T1/Name}"></GridViewColumn>
<GridViewColumn Header="Place" DisplayMemberBinding="{Binding Path=T2/Name}"></GridViewColumn>
</GridView>
</ListView.View>
</ListView>
<!--<Button Height="19" HorizontalAlignment="Right" Name="button2" VerticalAlignment="Top" Width="46" Margin="0,42,63,0" Click="button2_Click">Add</Button>-->
<Button Height="19" HorizontalAlignment="Right" Name="button1" VerticalAlignment="Top" Width="46" Click="button1_Click" Margin="0,43,63,0">Add</Button>
My Code
Dt1 = new DataTable("T1");
Dt1.Columns.Add("Name");
Dt1.Rows.Add("abc1");
Dt1.Rows.Add("abc2");
Dt2 = new DataTable("T2");
Dt2.Columns.Add("Name");
Dt2.Rows.Add("xyz1");
Dt2.Rows.Add("xyz1");
Ds = new DataSet();
Ds.Tables.Add(Dt1);
Ds.Tables.Add(Dt2);
lst.DataContext = Ds;
Hi am in full accord with Andy and Thomas. They both have explained the concept elegantly.
I am only showing the steps of doing the same only with dataset.
The MVVM (ModelView ViewModel) I am not discussing here.
The Xaml looks like this
<Grid Name="myGrid" ShowGridLines="False">
<Label Height="28" Margin="12,5,0,0" Name="lblName" VerticalAlignment="Top" HorizontalAlignment="Left" Width="55">Name</Label>
<TextBox Height="23" Margin="73,8,85,0" Name="txtName" VerticalAlignment="Top" />
<Label Height="28" Margin="12,39,0,0" Name="lblPlace" VerticalAlignment="Top" HorizontalAlignment="Left" Width="55">Place</Label>
<TextBox Height="23" Margin="73,44,85,0" Name="txtPlace" VerticalAlignment="Top" />
<Button Height="23" HorizontalAlignment="Left" Margin="20,82,0,0" Name="btnAddRecord" VerticalAlignment="Top" Width="75" Click="btnAddRecord_Click">Add Record</Button>
<ListView Margin="31,119,27,45" Name="listView" *ItemsSource="{Binding}"*>
<ListView.View>
<GridView>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn Header="Place" DisplayMemberBinding="{Binding Place}"/>
</GridView>
</ListView.View>
</ListView>
</Grid>
In the .CS file create a dataset
private DataSet MyDataSet()
{
DataTable dtInformation1 = new DataTable();
dtInformation1.Columns.Add("Name");
dtInformation1.Columns.Add("Place");
dtInformation1.Rows.Add(txtName.Text, txtPlace.Text);
DataTable dtInformation2 = new DataTable();
dtInformation2.Columns.Add("Name");
dtInformation2.Columns.Add("Place");
dtInformation2.Rows.Add(txtName.Text + "2", txtPlace.Text + "2");
DataSet Ds = new DataSet();
Ds.Tables.Add(dtInformation1);
Ds.Tables.Add(dtInformation2);
return Ds;
}
Next in the Button's click event write the following
private void btnAddRecord_Click(object sender, RoutedEventArgs e)
{
**listView.ItemsSource = MyDataSet().Tables[0].DefaultView;
- OR -
listView.ItemsSource = MyDataSet().Tables[1].DefaultView;**
}
N.B.~ You cannot assign the source of the ListView a dataset.
Why ? You may ask?
A dataset, in simple terms , is a collection of data tables.
Suppose you have 5 different datatables. And say none of their column names as well as column numbers are same.
Now you have assigned all those to your dataset. How will the controls source know that which source it has to bind?
Inorder to overcome such a situation, either make a custom datatable that will have all the columns of those discreet datatables and assign the values to this custom one and then bind to the source.
Or you need to explicitly specify the datatable in the datasource
But I always prefer to use MVVM pattern for this kind of operations.
I'm not sure what you're trying to do here... Is that the result you expect ?
abc1 xyz1
abc2 xyz2
There is no relation between your tables, so the binding system can't guess which row of T1 you want to associate with which row of T2... You should either put all data in the same table, or use a DataRelation between the two tables (but that would require extra fields for the join). You would then set the DataTable as the ItemsSource, not the DataSet.
Alternatively, you could create a dedicated class to hold the data, as suggested by Andy
WPF Binding works off of properties. For example, consider the following Person object:
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
You could then modify the XAML for your ListView to display a collection of Person objects by doing the following:
<ListView Margin="15,89,63,73" Name="lst" ItemsSource="{Binding}">
<ListView.View>
<GridView>
<GridViewColumn Header="First Name"
DisplayMemberBinding="{Binding Path=FirstName}" />
<GridViewColumn Header="Last Name"
DisplayMemberBinding="{Binding Path=LastName}" />
</GridView>
</ListView.View>
</ListView>
This will display the object's first name in the first column, and their last name in the second column (assuming that the DataContext of the ListView is a collection of Person objects).
In theory, to bind the values in a DataTable to a ListView, you could set the ItemsSource to the DataTable's Rows property. The problem becomes that the DataRow class doesn't expose properties for its columns - there is only the Item property that takes an argument specifying the row. To my knowledge, XAML does not support properties that take arguments, so I don't think that it is possible to use a DataTable as the ItemsSource for a ListView.
You do have some other options, however. You could create a strongly typed DataSet, which would expose a DataTable with a property for each column. You can then bind each GridViewColumn to the correct property.
Another approach would be to not use a DataTable at all. Your data layer would still load the data from your source into the DataTable, but it would then convert that data into normal objects. You could create an instance of ObservableCollection, add each of the objects into it, and then bind the ListView to that. Each GridViewColumn would just bind to the corresponding property of the objects.
Updated:
In answer to OP's further question:
Can I use the xsd for the purpose?.It
holds a property for each datatable..
You need more than just a property for a DataTable. You'd also need a property for each value in each row of the DataTable. Otherwise there is no property for the ListView's columns to bind to.
This worked for me.
public partial class MainWindow : Window
{
public ObservableCollection<DataTable> _observableCollection =
new ObservableCollection<DataTable>();
public MainWindow()
{
InitializeComponent();
DataTable dt1 = new DataTable();
dt1.Columns.Add("OrderID");
dt1.Columns.Add("CustomerID");
dt1.Columns.Add("ProductID");
dt1.Rows.Add("test1", "test2", "test3");
DataTable dt2 = new DataTable();
dt2.Columns.Add("OrderID");
dt2.Columns.Add("CustomerID");
dt2.Columns.Add("ProductID");
dt2.Rows.Add("test4", "test5", "test6");
_observableCollection.Add(dtInformation1);
_observableCollection.Add(dtInformation2);
}
public ObservableCollection<DataTable> _Collection
{ get { return _observableCollection; } }
ListView XAML
<ListView Height="Auto"
HorizontalAlignment="Stretch"
Name="somename"
ItemsSource="{Binding _Collection}" VerticalAlignment="Stretch" Width="Auto" >
<GridViewColumn Header="OrderID" Width="auto" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button Tag="{Binding OrderID}" Content="{Binding OrderID}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Width="auto" DisplayMemberBinding="{Binding CustomerID}" Header="CustomerID" />
<GridViewColumn Width="auto" DisplayMemberBinding="{Binding ProductID}" Header="ProductID" />

Resources