Как лучше всего использовать WPF / Silverlight для простого раскрывающегося списка, в котором отображаются соответствующие данные? - PullRequest
0 голосов
/ 31 июля 2009

Ниже приведено простое приложение WPF, которое отображает клиентов с наибольшим количеством заказов , которые собираются из базы данных через LINQ-to-SQL в коде позади.

Как лучше всего расширить это приложение WPF, чтобы пользователь мог выбрать его из раскрывающегося списка, например ::10000*

  • Клиентов с наибольшим количеством заказов
  • Клиенты с наименьшим количеством заказов
  • Клиенты по городам
  • Заказчики по штату

а соответствующая коллекция будет показана?

Вот несколько идей:

  1. имеет много док-панелей со всеми загруженными данными, которые обрабатываются обработчиком событий как Visible / Collapse ( быстрый и грязный подход )
  2. имеет ContentControl, который заполняется через DelegateCommand в ViewModel , который каким-то образом заполняет ContentControl ViewModel, который затем присоединяется к представлению через конвертер в XAML
  3. используйте шаблон MVP и попросите Presenter заполнить ContentControl соответствующим представлением (привязанным к коллекциям Presenter), это позволит вам загружать данные только непосредственно перед их просмотром
  4. или есть способ сделать это в простом коде позади , но где данные будут загружаться только тогда, когда пользователь выбирает выбор в раскрывающемся списке

Как вы решаете эту распространенную отраслевую проблему в своих приложениях 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>

Code-Behind:

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 ]

2 голосов
/ 01 августа 2009

Я бы использовал шаблон Model-View-ViewModel, который очень популярен в приложениях WPF и Silverlight.

Модель

Класс клиента - это объект в модели. Вам также нужен репозиторий или класс обслуживания, чтобы возвращать коллекции клиентов на основе различных критериев. В Silverlight данные извлекаются асинхронно, что немного усложняет ситуацию. Создавая интерфейс или абстрактный базовый класс для этого хранилища или класса обслуживания, вы можете протестировать класс ViewModel без использования базы данных. Вместо этого вы можете смоделировать некоторые тестовые данные.

ViewModel

ViewModel подключается к представлению с помощью привязки данных и должен либо реализовывать INotifyPropertyChanged и / или INotifyCollectionChanged, либо предоставлять свои данные с использованием свойств зависимости. Первый подход часто проще реализовать и протестировать.

В вашем примере кажется, что вы просто хотите отсортировать одну и ту же коллекцию, используя различные критерии сортировки. Ваша ViewModel - это коллекция объектов клиента. Отображать клиентов довольно просто, и ViewModel может содержать объекты сущностей клиентов напрямую. В более сложных сценариях, например где клиенты могут быть отредактированы, вы захотите создать модель представления клиентов.

Ваша ViewModel может быть производной от ObservableCollection<T> или CollectionView. Последний класс недоступен в Silverlight, и вам придется развернуть свой собственный, реализовав ICollectionView.

В дополнение к тому, что ViewModel является коллекцией пользовательских объектов, ему также потребуются некоторые методы для определения порядка сортировки. На самом деле, возможно, разумнее добавить свойство SortOrder в ViewModel и применить к нему коллекцию при изменении этого свойства.

Одним из важных моментов является то, что ViewModel не знает о пользовательском интерфейсе и может тестироваться независимо от пользовательского интерфейса.

View

Представление является UserControl и реализовано с использованием XAML. Некоторые люди считают очень важным вообще не иметь никакого кода в представлении, но отсутствие команд в Silverlight требует либо некоторого кода, либо некоторых связанных с командами свойств (PRISM поддерживает это в Silverlight). *

DataContext для View устанавливается на ViewModel, и элементы View затем связываются с различными частями ViewModel с помощью привязки данных. Кнопки и другие активные элементы управления пользовательского интерфейса подключаются к методам и т. Д. В ViewModel. В WPF вы можете использовать команды, но в Silverlight вам нужен какой-то код позади или что-то похожее на команды.

Когда пользователь нажимает на элемент управления в представлении, действие направляется в ViewModel либо как вызов метода, либо как изменение свойства. Затем ViewModel обновляется, и привязка данных из View в ViewModel обеспечивает отображение обновленной информации для пользователя.

1 голос
/ 01 августа 2009

Вы можете сделать это с помощью простого кода очень легко. Добавьте следующий комбо над границей.

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

Если вы ищете более изощренный подход, я, вероятно, последую совету Мартина, в противном случае вам следует начать.

...