Вложенная в WPF привязка данных ListBox с использованием ViewModel - PullRequest
0 голосов
/ 17 сентября 2009

Это длинный. Я добавляю код, чтобы вы могли видеть, что я пытаюсь сделать. Дайте мне знать, если что-то не понятно

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

public class Item
{
    public string Name { get; set; }

    public IList<Item> SubItems { get; set; } // 

    public bool IsSelected { get; set; }
}
//Chicken Fried Chicken 
//A hearty boneless chicken breast, lightly breaded in our special seasonings and 
//golden fried. Served with garlic mashed potatoes, country gravy and seasonal vegetables
// from Applebees

//Item - Chicken Fried Chicken 
//SubItem- mashed potatoes
//SubItem- country gravy
//SubItem- seasonal vegetables
//SubItem- Fries
//SubItem- Sauted vegetables
//SubItem- House Salad

public class ItemViewModel : INotifyPropertyChanged, IItemViewModel
{


    ObservableCollection<Item> selectedData = new ObservableCollection<Item>();

    private ObservableCollection<Item> todaysItems;
    public ObservableCollection<Item> TodaysItems
    {
        get { return todaysItems; }
        private set
        {
            if (todaysItems != value)
            {
                todaysItems = value;
                PropertyChanged(this, new PropertyChangedEventArgs("todaysItems"));
            }
        }
    }



    public ItemViewModel(IItemView itemView)
    {
        this.View = itemView;
        this.View.Model = this;

        List<Item> items = service.GetAllTestItems();
        TodaysItems = new ObservableCollection<Item>(items);

        selectedData.CollectionChanged += (sender, e) => UpdateSummary();
    }



    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged = delegate { };
    private void NotifyPropertyChanged(string propertyName)
    {
        var handler = this.PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    #endregion


    // How to get Selected Items from ListBox

    public ObservableCollection<Item> SelectedData
    {
        get { return selectedData; }
        set
        {
            selectedData = value;
        }
    }


    private void UpdateSummary()
    {
        // here I can get selected data , I can find which Item is selected and then update its SubItems IsSelected (CLR) Property
        // but something is not right here
    }
}

XAML

<UserControl x:Class="ItemView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:prism="clr-namespace:Microsoft.Practices.Composite.Presentation.Commands;assembly=Microsoft.Practices.Composite.Presentation"
             xmlns:ZCom="clr-namespace:MyProj.Infrastructure;assembly=Infrastructure">

    <Grid  >
        <ListBox ItemsSource="{Binding TodaysItems}">
            <ListBox.ItemTemplate>
                <DataTemplate >
                    <Border BorderThickness="1,1,1,1" CornerRadius="2,2,2,2" BorderBrush="Black">
                        <Grid   MinHeight="50" Width="150" Height="Auto" Margin="0,0,0,0">
                            <Grid.RowDefinitions>
                                <RowDefinition />
                                <RowDefinition/>
                                <RowDefinition />
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="150"/>
                                <ColumnDefinition Width="0"/>
                            </Grid.ColumnDefinitions>
                            <TextBlock Margin="4,4,2,2" Grid.Row="0"  Width="Auto" TextWrapping="Wrap" Text="{Binding Path=Name}"  />
                            <Grid Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" >
                                <Grid.Style>
                                    <Style>
                                        <Style.Triggers>
                                            <DataTrigger Binding="{Binding Path=IsSelected, RelativeSource=
                                                                    {RelativeSource Mode=FindAncestor,AncestorType={x:Type ListBoxItem}}
                                            }" Value="false">
                                                <Setter Property="Grid.Visibility" Value="Collapsed"/>
                                            </DataTrigger>
                                        </Style.Triggers>
                                    </Style>
                                </Grid.Style>
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="35"/>
                                    <RowDefinition Height="*"/>
                                </Grid.RowDefinitions>
                                <TextBlock Margin="2,4,2,2"  Grid.Row="0" Width="Auto" FontSize="10" FontStyle="Italic"  TextWrapping="Wrap"  Text="{Binding Path=Note}"/>

                                <ListBox Style="{DynamicResource MyStyle}" Grid.Row="1"  ItemsSource="{Binding Path=Modifiers}"  SelectionMode="Multiple"
                                         ZCom:ListBoxHelper.SelectedItems="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.SelectedData}">
                                    <ListBox.ItemTemplate>
                                        <DataTemplate >
                                            <TextBlock Margin="2,2,2,2"  TextWrapping="Wrap" Text="{Binding Path=Name}"  />
                                        </DataTemplate>

                                    </ListBox.ItemTemplate>
                                </ListBox>
                            </Grid>

                        </Grid>
                    </Border>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</UserControl>

Я использую ListBoxHelper (в инфраструктуре) из http://marlongrech.wordpress.com/2009/06/02/sync-multi-select-listbox-with-viewmodel/

Я получаю представление с Item и SubItems.

1) Как лучше установить свойство IsSelected подэлементов из вложенного ListBox

Я добавлю команду, которая будет сохранять выбранный элемент в базе данных после двойного щелчка. Подэлементы будут сохранены как дочерняя запись на основе значения IsSelected.

2) Есть ли способ сделать свойство SubItems класса c # наблюдаемым. Я бы не хотел вносить изменения, добавив Observable к объекту, так как он будет в другой сборке и может использоваться другими приложениями.

Редактировать 1: Нашел несколько полезный вопрос

WPF Привязка данных к шаблонам составных классов

Но опять же для этого мне придется наследовать от INotifyPropertyChanged.

Редактировать 2: Позвольте мне посмотреть, смогу ли я объяснить лучше - ListBox1 - режим одиночного выбора, а parent & ListBox 2 - множественный выбор. ListBox1 привязан (источник элемента) к свойству, которое возвращает наблюдаемый набор. ListBox2 привязан к свойству в классе элементов (Item.SubItems), которое возвращает IList. Класс элемента имеет свойство IsSelected. Я хочу иметь возможность выбирать подэлементы, которые должны установить для свойства IsSelected для подэлементов значение true. Зная, что в Item Item нет наследования INotifyPropertyChanged, как мне этого добиться. Я предполагаю, что если подэлементы не попадают под некоторую наблюдаемую коллекцию, любые изменения не будут сообщаться обратно источнику. Используя свойство selectedData, я могу обновить подэлементы, найдя родительский Item, но затем, чтобы обновить представление, мне потребуется firePropertChanged для «items», который включает все элементы и подэлементы. Я хочу, чтобы только изменение подпунктов было уведомлено механизмом привязки. Извините, если мне все еще не ясно.

Редактировать 3:

Думаю, нет другого пути, кроме как реализовать INotifyPropertyChanged для класса Item. Другим способом было бы реализовать модель представления, которая очень специфична для потребностей представления, но это добавит много кода.

1 Ответ

0 голосов
/ 17 сентября 2009

Это немного сбивает с толку, какова ваша общая цель здесь.

Если вы просто пытаетесь получить выбранные элементы из вложенного ListBox, пытались ли вы дать вашему ListBox x:Name и выставить ваши SelectedItems через свойство в вашем классе UserControl (ItemView)?

public IList SelectedItems
{
  get { return nestedListBox.SelectedItems; }
}
...