Reputation: 235
I have a UserControl called ContactExpander
<UserControl x:Class="Outreach_Alpha2.ContactExpander"
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"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
xmlns:outreach="clr-namespace:Outreach_Alpha2"
mc:Ignorable="d"
d:DesignHeight="225" d:DesignWidth="400">
<Border BorderBrush="Black" BorderThickness="1" CornerRadius="1" Margin="1">
<telerik:RadExpander Header="{Binding Path=ContactHeader}" x:Name="ExpanderRoot">
<StackPanel>
<DockPanel>
<StackPanel>
<Label Content="Name" FontWeight="Bold" Margin="0, 26, 0, 0"/>
<Label Content="Position" FontWeight="Bold"/>
<Label Content="Email" FontWeight="Bold"/>
<Label Content="Phone" FontWeight="Bold"/>
<Label Content="Fax" FontWeight="Bold"/>
</StackPanel>
<StackPanel>
<DockPanel>
<Label Content="Title" Width="50" Margin="1" HorizontalContentAlignment="Center"/>
<Label Content="First" Width="125" Margin="1" HorizontalContentAlignment="Center"/>
<Label Content="MI" Width="30" Margin="1" HorizontalContentAlignment="Center"/>
<Label Content="Last" Width="125" Margin="1" HorizontalContentAlignment="Center"/>
</DockPanel>
<DockPanel HorizontalAlignment="Left">
<!-- Title -->
<ComboBox Width="50" Margin="1"
SelectedValue="{Binding Path=Title,
Mode=TwoWay}"
ItemsSource="{Binding Path=TitleSource,
Mode=TwoWay}"/>
<!-- First Name -->
<TextBox Width="125" Margin="1"
Text="{Binding Path=FirstName,
Mode=TwoWay,
NotifyOnValidationError=True,
ValidatesOnExceptions=True}" />
<!-- Middle Initial -->
<TextBox Width="30" Margin="1"
Text="{Binding Path=MiddleInitial,
Mode=TwoWay}"/>
<!-- Last Name -->
<TextBox Width="127" Margin="1"
Text="{Binding Path=LastName,
Mode=TwoWay,
NotifyOnValidationError=True,
ValidatesOnExceptions=True}"/>
</DockPanel>
<!-- Position -->
<TextBox Margin="2" Text="{Binding Path=Position,
Mode=TwoWay}"/>
<!-- Email -->
<TextBox Margin="2" Text="{Binding Path=Email,
Mode=TwoWay,
NotifyOnValidationError=True,
ValidatesOnExceptions=True}"/>
<DockPanel>
<!-- Phone Number -->
<telerik:RadMaskedNumericInput Margin="2" BorderBrush="LightGray"
Value="{Binding Path=PhoneNumber,
Mode=TwoWay,
NotifyOnValidationError=True,
ValidatesOnExceptions=True}" />
<Label Content="Ext." FontWeight="Bold"/>
<!-- Phone Extension -->
<telerik:RadMaskedNumericInput Margin="2" Mask="" BorderBrush="LightGray"
Text="{Binding Path=PhoneExtension,
Mode=TwoWay,
NotifyOnValidationError=True,
ValidatesOnExceptions=True}"/>
</DockPanel>
<!-- Fax Number -->
<telerik:RadMaskedNumericInput Margin="2" BorderBrush="LightGray"
Value="{Binding Path=FaxNumber,
Mode=TwoWay,
NotifyOnValidationError=True,
ValidatesOnExceptions=True}"/>
</StackPanel>
</DockPanel>
<Border BorderBrush="Black" BorderThickness="0,0,0,1" Margin="0 6" />
<Button Content="Edit" Width="50" FontWeight="Bold" Margin="1"/>
</StackPanel>
</telerik:RadExpander>
</Border>
</UserControl>
I also have a ViewModelBase called ContactViewModel
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Telerik.Windows.Controls;
namespace Outreach_Alpha2
{
class ContactViewModel : ViewModelBase
{
//Declare contact variables
private string _title;
private string _firstName;
private string _middleInitial;
private string _lastName;
private string _position;
private string _email;
private string _phoneNumber;
private string _phoneExtension;
private string _faxNumber;
public string ContactHeader { get; set; }
public ObservableCollection<string> TitleSource { get; set; }
//First Name
//Set regex
public string Title
{
get { return _title; }
set
{
if (_title != value)
{
Validator.ValidateProperty(value, new ValidationContext(this, null, null) { MemberName = "Title" });
_title = value;
OnPropertyChanged("Title");
}
}
}
//First Name
[Required(AllowEmptyStrings = false)]
[RegularExpression(@"\b^[A-Z][a-zA-Z '&-]*[A-Za-z]$\b", ErrorMessage = @"Invalid First Name.")]
public string FirstName
{
get { return _firstName; }
set
{
if (_firstName != value)
{
Validator.ValidateProperty(value, new ValidationContext(this, null, null) { MemberName = "FirstName" });
_firstName = value;
OnPropertyChanged("FirstName");
}
}
}
//MiddleInitial
//Set regex
public string MiddleInitial
{
get { return _middleInitial; }
set
{
if (_middleInitial != value)
{
Validator.ValidateProperty(value, new ValidationContext(this, null, null) { MemberName = "MiddleInitial" });
_middleInitial = value;
OnPropertyChanged("MiddleInitial");
}
}
}
//Last Name
[Required(AllowEmptyStrings = false)]
[RegularExpression(@"\b^[A-Z][a-zA-Z '&-]*[A-Za-z]$\b", ErrorMessage = @"Invalid last name.")]
public string LastName
{
get { return _lastName; }
set
{
if (_lastName != value)
{
Validator.ValidateProperty(value, new ValidationContext(this, null, null) { MemberName = "LastName" });
_lastName = value;
OnPropertyChanged("LastName");
}
}
}
//Position
//Set regex
public string Position
{
get { return _position; }
set
{
if (_position != value)
{
Validator.ValidateProperty(value, new ValidationContext(this, null, null) { MemberName = "Position" });
_position = value;
OnPropertyChanged("Position");
}
}
}
//Email
//Set regex
public string Email
{
get { return _email; }
set
{
if (_email != value)
{
Validator.ValidateProperty(value, new ValidationContext(this, null, null) { MemberName = "Email" });
_email = value;
OnPropertyChanged("Email");
}
}
}
//Phone Number
//Set regex
public string PhoneNumber
{
get { return _phoneNumber; }
set
{
if (_phoneNumber != value)
{
Validator.ValidateProperty(value, new ValidationContext(this, null, null) { MemberName = "PhoneNumber" });
_phoneNumber = value;
OnPropertyChanged("PhoneNumber");
}
}
}
//Phone Extension
//Set regex
public string PhoneExtension
{
get { return _phoneExtension; }
set
{
if (_phoneExtension != value)
{
Validator.ValidateProperty(value, new ValidationContext(this, null, null) { MemberName = "PhoneExtension" });
_phoneExtension = value;
OnPropertyChanged("PhoneExtension");
}
}
}
//Fax Number
//Set regex
public string FaxNumber
{
get { return _faxNumber; }
set
{
if (_faxNumber != value)
{
Validator.ValidateProperty(value, new ValidationContext(this, null, null) { MemberName = "FaxNumber" });
_faxNumber = value;
OnPropertyChanged("FaxNumber");
}
}
}
}
}
I have multiple contacts I'd like to keep track of for one company. I will retrieve the contacts from a SQL database and I want the application to autogenerate multiple expanders in a stackpanel like the following.
<ScrollViewer Height="350" VerticalScrollBarVisibility="Auto" CanContentScroll="True">
<DockPanel>
<StackPanel Name="ContactStackPanel" Margin ="16" >
<!-- Expanders will populate here from the code behind -->
</StackPanel>
</DockPanel>
</ScrollViewer>
I do not know how to go about binding the ContactViewModel
to the ContactExpander
user control.
Upvotes: 1
Views: 194
Reputation: 3404
In order for any bindings to be hooked up, you need to set the DataContext
property of the element view to an instance of the viewmodel. The DataContext
acts as the source for all of your bindings (unless the binding itself specifies a custom source). You can then set your bindings as normal using the {Binding PropertyName}
syntax in xaml. The DataContext
will work for the element you set it on as well as all descendants of that element.
As a separate point, you really should not be populating the children of a StackPanel
dynamically from a code-behind. WPF provides an automated way of doing that sort of thing using a control called ItemsControl. You just bind the ItemsSource
property to an ObservableCollection<ContactViewModel>
property that you define and set the ItemTemplate
property to a DataTemplate
containing your view. Then, all you have to do from that point on is manage the items in your collection and let ItemsControl
manage adding, removing and sorting the views. It is also very customizable if the default layout doesn't suit your needs.
Upvotes: 1