【问题标题】:Binding ListView with DataTemplates containing UserControls to ViewModels in MVVM将 ListView 与包含 UserControls 的 DataTemplates 绑定到 MVVM 中的 ViewModels
【发布时间】:2014-04-29 01:02:53
【问题描述】:

我对 MVVM 很陌生,所以请耐心等待。

我正在开发一个包含联系人列表的应用程序。我使用以下模型定义了一个联系人用户控件:

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

还有下面的 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();
}

还有以下视图:

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

现在,我想创建一个用户控件,其中包含以下 ViewModel 中定义的联系人列表:

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

还有下面的视图:

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

问题是ClientsListView中的ClientView ListViewItems没有正确绑定到ClientViewModels的ObservableCollection。如果我添加更多 ClientViewModel,列表中会显示正确数量的 ClientView,但 ClientView 中没有任何标签被填充。

谁能告诉我我做错了什么?非常感谢任何反馈!

【问题讨论】:

  • 您需要向我们提供一些线索,了解是什么让您认为这是错误的。到目前为止,您所写的内容没有明显的问题。
  • 对不起加里。我编辑了帖子以添加我的问题。
  • 我现在可以看到问题了。讨厌的虫子。用于指定客户端视图的数据上下文的 Xaml 使用空客户端创建视图。您需要在客户端视图 xaml 中更改数据上下文的声明。
  • ClientView 的 DataContext 声明需要是什么样的?是否需要将 DataContext 声明移至 ClientViewModel?

标签: c# wpf mvvm datatemplate datacontext


【解决方案1】:

这里的问题是您正在 InitializeComponent 方法中为客户端视图构建数据上下文。这是由于 Xaml 中的静态声明。您可以通过将这行代码添加到 ClientView 构造函数来凭经验证明这一点...

    var dc = this.DataContext;

并观察它是在“错误的时间”用空值创建的。

如果您在 ClientView.xaml 中更改这些行...

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

到这个...

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

您将看到您的客户按您预期的方式填充和显示。您需要更改设计策略以考虑 InitializeComponent 的行为方式,但这个答案会让您“陷入困境”。

【讨论】:

  • 谢谢!在我进行更改后,它按预期工作。
猜你喜欢
  • 2020-12-29
  • 2012-04-17
  • 2010-11-04
  • 1970-01-01
  • 2012-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多