Frage

I'm pretty new to MVVM so bear with me.

I'm working on an application that contains a contacts list. I've defined a contact user control with the following model:

public class Client
{
    public string FirstName { get; set; }
    public string MiddleName { get; set; }
    public string LastName { get; set; }
    public string PhoneNumber { get; set; }
    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string ZipCode { get; set; }
    public int CustomerID { get; set; }

    public string FullName
    {
        get
        {
            string result = FirstName;

            if (string.IsNullOrEmpty(result))
                result = MiddleName;
            else if(!string.IsNullOrEmpty(MiddleName))
                result += string.Format(" {0}", MiddleName);

            if (string.IsNullOrEmpty(result))
                result = LastName;
            else if (!string.IsNullOrEmpty(LastName))
                result += string.Format(" {0}", LastName);

            if (string.IsNullOrEmpty(result))
                result = "";

            return result;
        }
    }
}

And the following ViewModel:

public class ClientViewModel : ObservableObject
{
    public Client Customer
    {
        get
        {
            return _customer;
        }
        set
        {
            _customer = value;
            RaisePropertyChangedEvent("Customer");
        }
    }
    public string FullName { get { return _customer.FullName; } }
    public string PhoneNumber { get { return _customer.PhoneNumber; } }
    public string Address1 { get { return _customer.Address1; } }
    public string Address2 { get { return _customer.Address2; } }
    public string City { get { return _customer.City; } }
    public string State { get { return _customer.State; } }
    public string ZipCode { get { return _customer.ZipCode; } }

    Client _customer = new Client();
}

And the following View:

<UserControl x:Class="LawnCareManager.Views.ClientView"
             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:local="clr-namespace:LawnCareManager.ViewModels"
             mc:Ignorable="d" 
             d:DesignHeight="180" d:DesignWidth="300">
    <UserControl.DataContext>
        <local:ClientViewModel/>
    </UserControl.DataContext>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="1*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>
        <Label Grid.Row="0"
               Grid.Column="0"
               VerticalAlignment="Center"
               HorizontalAlignment="Right"
               Margin="10,0,0,0"
               Content="Name: "/>

        <Label Grid.Row="0"
               Grid.Column="1"
               VerticalAlignment="Center"
               HorizontalAlignment="Left"
               Margin="10,0,0,0"
               Content="{Binding FullName}"/>

        <Label Grid.Row="1"
               Grid.Column="0"
               VerticalAlignment="Center"
               HorizontalAlignment="Right"
               Margin="10,0,0,0"
               Content="Phone Number: "/>

        <Label Grid.Row="1"
               Grid.Column="1"
               VerticalAlignment="Center"
               HorizontalAlignment="Left"
               Margin="10,0,0,0"
               Content="{Binding PhoneNumber}"/>

        <Label Grid.Row="2"
               Grid.Column="0"
               VerticalAlignment="Center"
               HorizontalAlignment="Right"
               Margin="10,0,0,0"
               Content="Address 1: "/>

        <Label Grid.Row="2"
               Grid.Column="1"
               VerticalAlignment="Center"
               HorizontalAlignment="Left"
               Margin="10,0,0,0"
               Content="{Binding Address1}"/>

        <Label Grid.Row="3"
               Grid.Column="0"
               VerticalAlignment="Center"
               HorizontalAlignment="Right"
               Margin="10,0,0,0"
               Content="Address 2: "/>

        <Label Grid.Row="3"
               Grid.Column="1"
               VerticalAlignment="Center"
               HorizontalAlignment="Left"
               Margin="10,0,0,0"
               Content="{Binding Address2}"/>

        <Label Grid.Row="4"
               Grid.Column="0"
               VerticalAlignment="Center"
               HorizontalAlignment="Right"
               Margin="10,0,0,0"
               Content="City: "/>

        <Label Grid.Row="4"
               Grid.Column="1"
               VerticalAlignment="Center"
               HorizontalAlignment="Left"
               Margin="10,0,0,0"
               Content="{Binding City}"/>

        <Label Grid.Row="5"
               Grid.Column="0"
               VerticalAlignment="Center"
               HorizontalAlignment="Right"
               Margin="10,0,0,0"
               Content="State: "/>

        <Label Grid.Row="5"
               Grid.Column="1"
               VerticalAlignment="Center"
               HorizontalAlignment="Left"
               Margin="10,0,0,0"
               Content="{Binding State}"/>

        <Label Grid.Row="6"
               Grid.Column="0"
               VerticalAlignment="Center"
               HorizontalAlignment="Right"
               Margin="10,0,0,0"
               Content="Zip Code: "/>

        <Label Grid.Row="6"
               Grid.Column="1"
               VerticalAlignment="Center"
               HorizontalAlignment="Left"
               Margin="10,0,0,0"
               Content="{Binding ZipCode}"/>
    </Grid>
</UserControl>

Now, I want to create a user control that contains a list of contacts defined in the ViewModel below:

public class ClientsListViewModel : ObservableObject
{
    public ObservableCollection<ClientViewModel> Clients
    {
        get { return _clients; }
        set { _clients = value; }
    }

    ObservableCollection<ClientViewModel> _clients = new ObservableCollection<ClientViewModel>();

    public ClientsListViewModel()
    {
        ClientViewModel client = new ClientViewModel();
        client.Customer.FirstName = "John";
        client.Customer.LastName = "Doe";
        client.Customer.PhoneNumber = "555-555-5555";
        client.Customer.Address1 = "1234 Fake Street";
        client.Customer.City = "Springfield";
        _clients.Add(client);
    }
}

And the View below:

<UserControl x:Class="LawnCareManager.Views.ClientsListView"
             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:local="clr-namespace:LawnCareManager.ViewModels"
             xmlns:views="clr-namespace:LawnCareManager.Views"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <UserControl.DataContext>
        <local:ClientsListViewModel/>
    </UserControl.DataContext>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>

        <Label Content="Contacts"
               Grid.Row="0"
               Grid.Column="0"/>
        <ListView Grid.Column="1" Grid.Row="2" Grid.ColumnSpan="2" ItemsSource="{Binding Clients}" x:Name="listView">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <views:ClientView DataContext="{Binding}"/>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </Grid>
</UserControl>

The problem is that the ClientView ListViewItems in the ClientsListView are not binding correctly to the ObservableCollection of ClientViewModels. The correct number of ClientViews shows up in the list if I add more ClientViewModels, but none of the labels in the ClientView are populating.

Could somebody tell me what I'm doing wrong? Any feedback is greatly appreciated!

War es hilfreich?

Lösung

The issue here is that you are constructing the data context for client view within the InitializeComponent method. That's due to the static declaration in your Xaml. You can prove this empirically by adding this line of code to the ClientView constructor...

    var dc = this.DataContext;

and observe that it gets created with null values at the "Wrong time".

If you change these lines in your ClientView.xaml...

<UserControl.DataContext>
    <genericMvvm1:ClientViewModel/>
</UserControl.DataContext>

to this...

   <!--<UserControl.DataContext>
        <genericMvvm1:ClientViewModel/>
    </UserControl.DataContext>-->

You will see your clients getting populated and displayed the way you were expecting. You'll need to change your design strategy to take account of the way InitializeComponent behaves, but this answer gets you 'unstuck'.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top