Reputation: 536
I'm playing around with WPF and LINQ, and stuck at the following point with no clue on how to show a single record, all of the examples I found show how to present a list, but not a single record.
I have prepared a user control that should show one record at a time, in my example a Customer, showing its' Id, Given Name and Surname, here it is:
<UserControl x:Class="SportsClubsManagement.CustomersManagement.CustomerData"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="500">
<Grid DataContext="Binding Customer">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="Id" Height="30" Width="70" />
<TextBox Grid.Row="0" Grid.Column="1" Height="20" Width="70" Name="Id" Text="{Binding Path=Id}" />
<Label Grid.Row="1" Grid.Column="0" Content="Given Name" Height="30" Width="70" />
<TextBox Grid.Row="1" Grid.Column="1" Height="20" Width="70" Name="GivenName" Text="{Binding Path=GivenName}" />
<Label Grid.Row="1" Grid.Column="2" Content="Surname" Height="30" Width="70" />
<TextBox Grid.Row="1" Grid.Column="3" Height="20" Width="70" Name="Surname" Text="{Binding Path=Surname}" />
<Button Grid.Row="2" Grid.Column="0" Content="New record" />
<Button Grid.Row="2" Grid.Column="3" Content="Next record" />
<Button Grid.Row="2" Grid.Column="2" Content="Prev record" />
</Grid>
</UserControl>
I also have created a table with several records and a class to represent a customer which also implements INotifyPropertyChanged.
[Table(Name = "Customers")]
public class Customer : INotifyPropertyChanged
{
#region Fields
private String id;
private String givenName;
private String surname;
#endregion
#region Properties
[Column(IsPrimaryKey=true, Storage="id", Name="Id")]
public String Id
{
get { return this.id; }
}
[Column(Storage="givenName", Name="GivenName")]
public String GivenName
{
get { return this.givenName; }
set {
if (this.givenName != value)
{
this.givenName = value;
this.OnPropertyChanged("GivenName");
}
}
}
[Column(Storage="surname", Name="Surname")]
public String Surname
{
get { return this.surname; }
set {
if (this.surname != value)
{
this.surname = value;
this.OnPropertyChanged("Surname");
}
}
}
#endregion
#region INotifyPropertyChanged Members"
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(String name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
#endregion
}
Now in the code behind the user control I have a realy simple code that connect to the db and gets a record:
public partial class CustomerData : UserControl
{
private int curCustSeqNum;
private Data.Customer customer;
public Data.Customer Customer
{
get
{
return customer;
}
set
{
this.customer = value;
}
}
private IQueryable<Data.Customer> custQuery;
public CustomerData()
{
InitializeComponent();
DataContext db = new DataContext(@"server=WIN-EL78137MUMS\SQLEXPRESS;database=PlayGround;integrated security=SSPI");
// Get a typed table to run queries.
Table<Data.Customer> Customers = db.GetTable<Data.Customer>();
//db.Log = Console.Out;
custQuery =
from cust in Customers
orderby cust.Id
select cust;
curCustSeqNum = 0;
Customer = custQuery.Skip(curCustSeqNum).Take(1).First();
}
}
But how can I bind the textboxes to the current selected Customer? You can see my last guess, after defining resources etc. But every time I miss something. I would like to know how can I achieve that in XAML, and in code behind. Basically after that I would be able to use the curCustSeqNum to skip to the following record.
Upvotes: 0
Views: 178
Reputation: 43616
The CustomerData
does not implement INotifyPropertyChanged
so when you set Customer in the constructor the xaml has no Idea it has changed.
Example:
public partial class CustomerData : UserControl, INotifyPropertyChanged
{
private int curCustSeqNum;
private Data.Customer customer;
private IQueryable<Data.Customer> custQuery;
public Data.Customer Customer
{
get { return customer; }
set { this.customer = value; OnPropertyChanged("Customer"); }
}
public CustomerData()
{
InitializeComponent();
// set the datacontext
DataContext = this;
................
Customer = custQuery.Skip(curCustSeqNum).Take(1).First();
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(String name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}
also mentioned by someone else, you DataContext binding on the Grid is invalid
<Grid DataContext="Binding Customer">
should be
<Grid DataContext="{Binding Customer}">
Upvotes: 1
Reputation: 303
Try set your Datacontext to
DataContext="{Binding Path=Customer}"
I realise that path is implied, however i have run into this problem myself and this solved it for me.
Upvotes: 0
Reputation: 13176
Typically you'd make a "CurrentItem" object inside of your ViewModel in which you'd initialize on a SelectionCommand. In your case, you'd bind your "Customer" on your SelectionCommand in which you'd run a Customer.Get(id) command to obtain the current customer. You can then bind your controls to the "CurrentCustomer" object of the fields for each control.
Upvotes: 0