0

So I have some data hardcoded at the moment but intend to query a SQL database to populate some fields.

I want to populate this StackPanel with ContactExpander UserControls as needed:

<ScrollViewer Height="350" VerticalScrollBarVisibility="Auto" CanContentScroll="True">
    <DockPanel>
        <StackPanel Name="ContactStackPanel" Margin ="16">
            <!-- Autopopulate the usercontrols here -->
        </StackPanel>
    </DockPanel>
</ScrollViewer>

The ContactViewModel goes as follows:

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");
                }
            }
        }
    }
}

The ContactExpander UserControl template is as follows:

<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}">
            <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>

This is the codebehind for the ContactExpander UserControl:

namespace Outreach_Alpha2
{
    /// <summary>
    /// Interaction logic for ContactExpander.xaml
    /// </summary>
    public partial class ContactExpander : UserControl
    {
        public ContactExpander()
        {
            InitializeComponent();
            this.DataContext = new ContactViewModel();
        }
    }
}

I have a custom structure that contains the following:

public class ContactInfo
{
    public String FirstName { get; set; }
    public String MiddleInitial { get; set; }
    public String LastName { get; set; }
    public String Title { get; set; }
    public String Position { get; set; }
    public long PhoneNumber { get; set; }
    public int PhoneExtension { get; set; }
    public long FaxNumber { get; set; }
    public String Email { get; set; }
    public String CurrentUser { get; set; }
}

I populate these fields like this:

var contactList = new List<ContactInfo>()
{
    new ContactInfo(){ FirstName = "John", MiddleInitial = "", LastName = "Doe", Title = "Dr.", Position = "CEO", PhoneNumber = 8005551234, PhoneExtension = 1234, FaxNumber = 3615559876, Email = "john.doe@abc.com", CurrentUser = ""},
    new ContactInfo(){ FirstName = "Jane", MiddleInitial = "", LastName = "Doe", Title = "Mrs.", Position = "", PhoneNumber = 8005551235, PhoneExtension = 1234, Email = "jane.doe@abc.com", CurrentUser = ""},
};

I just do not know where to go from here. I do not know how to auto populate the ContactExpander UserControl with bindings to the ViewModel and I do not know how to auto populate the Stackpanel with the auto populated ContactExpanders.

Chris
  • 235
  • 2
  • 14
  • What is ContactExpander ? is that the usercontrol you want to bind with view model ? – Abin May 28 '15 at 16:49
  • 1
    You bind your models to ContentControls or ItemsControls and use DataTemplates. These controls seek out the appropriate template for the binding type and load them into the UI. Here's a very stripped down example of how this works. Try it in a prototype and learn how it works. http://stackoverflow.com/a/30239654/1228 –  May 28 '15 at 16:52
  • 1
    Here's another, more complex example, but it uses a HierarchicalDataTempate http://stackoverflow.com/questions/28993566/simple-nested-treeview-xaml-structure/28994128#28994128 –  May 28 '15 at 16:55
  • 1
    http://stackoverflow.com/a/7389529/1228 and http://stackoverflow.com/questions/6537694/how-do-i-create-a-viewmodel-based-on-the-datacontext-object-of-a-datatemplate/6538086#6538086 are good as well. –  May 28 '15 at 16:58
  • @Will, I guess where I'm confused is I don't know how to set the values to the MVVM. I have a List of ContactInfo datatypes but I don't know how to map that to the ViewModel. – Chris May 28 '15 at 18:54
  • You don't map it to the view model. You 1) expose properties on the view model, each holding a 2) model of a certain Type (in this case, ContactInfo), which is bound to a 3) ContentControl of some type, or a collection of #2 is bound to an ItemsControl of some type, and when bound this control searches for 4) a DataTemplate that matches this type. `` (assuming there is an xmlns:this). There are several examples of this in the answers/questions I linked. Try it in a prototype! –  May 28 '15 at 19:46
  • Also, a StackPanel is not an ItemsControl. You need to use it or a control that extends it. If you're unable to figure this out, let me know, i can dig out an old example application and slap it in an answer. –  May 28 '15 at 20:11

0 Answers0