WPF / Silverlight中显示适当数据的简单下拉列表的最佳方法是什么?

时间:2009-07-31 15:54:18

标签: wpf silverlight linq-to-sql data-binding

下面是一个简单的WPF应用程序,它显示订单最多的客户,它是通过代码隐藏中的LINQ-to-SQL从数据库中收集的。

扩展此WPF应用程序的最佳方法是什么,以便用户可以从下拉列表中进行选择,例如:

  • 订单最多的客户
  • 订单最少的客户
  • 城市客户
  • 各州的客户

将显示相应的集合?

以下是一些想法:

  1. 有许多dockpanels加载了所有数据,这些数据被事件处理程序变为可见/折叠(快速而肮脏的方法
  2. 有一个ContentControl,它通过 ViewModel 中的DelegateCommand填充,它以某种方式用ViewModel填充ContentControl,然后通过XAML中的转换器将其附加到View
  3. 使用 MVP 模式,让Presenter使用适当的View(绑定到Presenter的集合)填充ContentControl,这样您就可以只在数据被查看之前加载
  4. 或者有没有办法在简单的代码隐藏中执行此操作,但只有在用户选择下拉列表中的选择时才会加载数据
  5. 您如何在WPF / Silverlight应用中解决这个常见的业务问题,即客户点击控件和屏幕区域会向他显示相应的信息?

    XAML:

    <Window x:Class="TestLinqToSql123.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="300" Width="500">
        <Window.Resources>
            <DataTemplate x:Key="CustomerTemplate">
                <TextBlock>
                    <TextBlock.Text>
                        <MultiBinding StringFormat="{}The customer {0} lives in {1} and has {2} orders.">
                            <Binding Path="Name"/>
                            <Binding Path="City"/>
                            <Binding Path="NumberOfOrders"/>
                        </MultiBinding>
                    </TextBlock.Text>
                </TextBlock>
            </DataTemplate>
    
        </Window.Resources>
        <DockPanel>
            <Border 
                Background="Orange"
                CornerRadius="5"
                Margin="10"
                Padding="10">
                <ScrollViewer>
                    <StackPanel>
                    <TextBlock Text="Customers with the most orders:"
                       Margin="0 0 0 10"
                       FontSize="18"/>
    
                    <ItemsControl x:Name="TheList"
                            ItemTemplate="{StaticResource CustomerTemplate}"/>
                    </StackPanel>
                </ScrollViewer>
            </Border>
        </DockPanel>
    </Window>
    

    代码隐藏:

    using System.Windows;
    using TestLinqToSql123.Models;
    using System.Linq;
    
    namespace TestLinqToSql123
    {
        public partial class Window1 : Window
        {
            public Window1()
            {
                InitializeComponent();
    
                NorthwindDataContext db = new NorthwindDataContext();
    
                var customers = from c in db.Customers
                                orderby c.Orders.Count descending
                                select new
                                {
                                    Name = c.ContactName,
                                    c.City,
                                    NumberOfOrders = c.Orders.Count
                                };
                TheList.ItemsSource = customers;
            }
        }
    }
    

2 个答案:

答案 0 :(得分:2)

我会使用在WPF和Silverlight应用程序中非常流行的Model-View-ViewModel模式。

模型

客户类是模型中的实体。您还需要一个存储库或服务类,以根据各种条件返回客户集合。在Silverlight中,异步检索数据会使事情变得复杂。通过为此存储库或服务类创建接口或抽象基类,您可以在不使用数据库的情况下测试ViewModel类。您可以改为模拟一些测试数据。

视图模型

ViewModel使用数据绑定连接到视图,它必须实现INotifyPropertyChanged和/或INotifyCollectionChanged或使用依赖项属性公开其数据。前一种方法通常更容易实施和测试。

在您的示例中,您似乎只想使用各种排序条件对相同的集合进行排序。然后,您的ViewModel就是客户对象的集合。显示客户非常简单,ViewModel可以直接包含客户实体对象。在更复杂的场景中,例如在可以编辑客户的地方,您可以创建客户视图模型。

您的ViewModel可以来自ObservableCollection<T>CollectionView。后者是Silverlight中没有的类,您必须通过实现ICollectionView来实现自己的类。

除了作为客户对象的集合之外,ViewModel还需要一些方法来确定要使用的排序顺序。实际上,向ViewModel添加SortOrder属性并在此属性更改时求助于集合可能更为明智。

重要的一点是ViewModel不了解用户界面,可以独立于用户界面进行测试。

视图

视图是UserControl,使用XAML实现。有些人发现在View中根本没有代码隐藏非常重要,但Silverlight中缺少命令需要一些代码隐藏或一些类似命令的附加属性(PRISM在Silverlight中支持这一点)。

View的DataContext设置为ViewModel,然后使用数据绑定将View的元素绑定到ViewModel的各个部分。按钮和其他活动用户界面控件连接到ViewModel上的方法等。在WPF中,您可以使用命令,但在Silverlight中,您需要一些代码隐藏或与命令类似的东西。

当用户单击View中的控件时,操作将作为方法调用或属性更改路由到ViewModel。然后更新ViewModel,从View到ViewModel的数据绑定可确保向用户显示更新的信息。

答案 1 :(得分:1)

您可以非常轻松地在简单的代码隐藏中执行此操作。在边框上方添加以下组合。

<ComboBox 
    x:Name="SelectionCombo" 
    DockPanel.Dock="Top" 
    SelectionChanged="ComboBox_SelectionChanged"
    >
    <ComboBoxItem x:Name="MostOrders">Customers with the most orders</ComboBoxItem>
    <ComboBoxItem x:Name="LeastOrders">Customers with the least orders</ComboBoxItem>
    <ComboBoxItem x:Name="ByCity">Customers by city</ComboBoxItem>
    <ComboBoxItem x:Name="ByState">Customers by state</ComboBoxItem>
</ComboBox>

然后在你的代码后面添加以下事件处理程序

private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    ComboBoxItem item = (ComboBoxItem)e.AddedItems[0];
    if (item == MostOrders)
        GetByMostOrders();
    else if (item == LeastOrders)
        GetByLeastOrders();
    else if (item == ByCity)
        GetByCity();
    else if (item == ByState)
        GetByState();
}

然后创建填充组合的方法

private void GetByMostOrders()
{
    NorthwindDataContext db = new NorthwindDataContext();

    var customers = from c in db.Customers
                    orderby c.Orders.Count descending
                    select new
                    {
                        Name = c.ContactName,
                        c.City,
                        NumberOfOrders = c.Orders.Count
                    };
    TheList.ItemsSource = customers;
}

如果您正在寻找更复杂的方法,我可能会遵循马丁的建议,否则这应该可以让您入手。