Динамически добавлять действия eventtocommand в список - PullRequest
2 голосов
/ 25 июня 2011

У меня есть страница с

пространств имен:

xmlns:Custom="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 
xmlns:GalaSoft_MvvmLight_Command="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WP7" 

xaml во время разработки:

<ListBox  x:Name="ItemGroupsList" ItemsSource="{Binding ItemGroups}" Height="496" 
                SelectedItem="{Binding SelectedItemGroup, Mode=TwoWay}" >
    <Custom:Interaction.Triggers>
         <Custom:EventTrigger EventName="SelectionChanged">
             <GalaSoft_MvvmLight_Command:EventToCommand 
                     x:Name="SelectionChangedEvent" 
                     Command="{Binding GoToEditItemGroupCommand, Mode=OneWay}" 
                     PassEventArgsToCommand="True"/>
        </Custom:EventTrigger>
    </Custom:Interaction.Triggers>

В коде я генерирую несколько списков во время выполнения и хотел бы иметь возможность привязываться к реле-команде в режиме просмотра, как приведенный выше код xaml, показанный выше ...

Как мне сделать вышеупомянутое во время выполнения в коде позади представления.

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

По сути, у меня есть панарома, и каждый элемент панаромы создается динамически, причем каждый элемент панаромы имеет список, который будет связан с моделью представления с помощью команд relay

1 Ответ

1 голос
/ 25 июня 2011

Примечание: см. Также соответствующий пост .

В этой статье описывается, как можно прикреплять поведения из кода позади.

Однако , я твердо не советовал бы вам идти по этому пути, если у вас нет настоятельной необходимости .Если вы используете этот подход в своем ViewModel, вы потеряете всю тестируемость, поскольку он генерирует ViewModel, который тесно связан с View и фактически не может жить без него.( Примечание: , по этой причине также не рекомендуется возвращать аргументы событий для ViewModel, используйте CommandParameter вместо того, чтобы возвращать DataContext, если необходимо).

Обычно вы можете заархивировать свою цель с помощью MVVM другим способом, и остальная часть поста описывает это.

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

Во-вторых, используйте шаблоны для создания и оформления ваших списков.Если вам нужно показать их только при выборе элемента, используйте конвертер BooleanToVisibility (, см. Здесь и свяжите свойство Visibility вложенных списков со свойством на ViewModel, используя конвертер.(не мой образец).

Образец создает ListBox, у которого есть ItemsSource, связанный со свойством Items ViewModel. Кроме того, он создает ContentControl, который имеет DataContext, связанный сSelectedItem из ViewModel. ContentControl затем снова содержит ListBox, где DataContext связан со свойством SubItem ItemViewModel. MainViewModel генерирует тестовые данные, которые будут показаныво время разработки и выполнения.

В остальной части поста показан пример:

1. XAML главной страницы (кроме):

        <ContentControl x:Name="target1" Grid.Row="1" DataContext="{Binding SelectedItem}" Margin="20,0">
            <ContentControl.Template>
                <ControlTemplate>
                    <StackPanel>
                        <StackPanel Orientation="Horizontal">
                            <TextBlock Text="Name:" Margin="0,0,10,0"/>
                            <TextBlock Text="{Binding Name}"/>
                        </StackPanel>
                        <ListBox ItemsSource="{Binding SubItems}">
                            <ListBox.ItemContainerStyle>
                                <Style TargetType="ListBoxItem">
                                    <Setter Property="Padding" Value="1"/>
                                    <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
                                </Style>
                            </ListBox.ItemContainerStyle>
                            <ListBox.ItemTemplate>
                                <DataTemplate>
                                    <Border Background="navy" BorderBrush="White" BorderThickness="1">
                                        <TextBlock Text="{Binding Name}"/>
                                    </Border>
                                </DataTemplate>
                            </ListBox.ItemTemplate>
                        </ListBox>
                    </StackPanel>
                </ControlTemplate>
            </ContentControl.Template>
        </ContentControl>
    </Grid>
</Grid>

2. Модель основного вида

    public MainViewModel()
    {
        // working with fields to ensure no events are fired during initial phase
        this._items = new ObservableCollection<ItemViewModel>();
        for (int i = 0; i < 5; ++i) {
            var item = new ItemViewModel() { Name = string.Format("Item {0}", i) };
            for (int j = 0; j < 3; ++j)
                item.SubItems.Add(new ItemViewModel() { Name = string.Format("{0} - Sub Item {1}", item.Name, j) });
            this._items.Add(item);
        }
        this.SelectedItem = this._items[0];

        if (IsInDesignMode) {
            // Code runs in Blend --> create design time data.
        } else {
            // Code runs "for real"
        }
    }

    #region [Items]

    /// <summary>
    /// The <see cref="Items" /> property's name.
    /// </summary>
    public const string ItemsPropertyName = "Items";

    private ObservableCollection<ItemViewModel> _items = default(ObservableCollection<ItemViewModel>);

    /// <summary>
    /// Gets the Items property.
    /// TODO Update documentation:
    /// Changes to that property's value raise the PropertyChanged event. 
    /// This property's value is broadcasted by the Messenger's default instance when it changes.
    /// </summary>
    public ObservableCollection<ItemViewModel> Items {
        get {
            return _items;
        }

        set {
            if (_items == value) {
                return;
            }

            var oldValue = _items;
            _items = value;

            // Update bindings, no broadcast
            RaisePropertyChanged(ItemsPropertyName);

            // Update bindings and broadcast change using GalaSoft.MvvmLight.Messenging
            //RaisePropertyChanged(ItemsPropertyName, oldValue, value, true);
        }
    }

    #endregion

    #region [SelectedItem]

    /// <summary>
    /// The <see cref="SelectedItem" /> property's name.
    /// </summary>
    public const string SelectedItemPropertyName = "SelectedItem";

    private ItemViewModel _selectedItem = default(ItemViewModel);

    /// <summary>
    /// Gets the SelectedItem property.
    /// TODO Update documentation:
    /// Changes to that property's value raise the PropertyChanged event. 
    /// This property's value is broadcasted by the Messenger's default instance when it changes.
    /// </summary>
    public ItemViewModel SelectedItem {
        get {
            return _selectedItem;
        }

        set {
            if (_selectedItem == value) {
                return;
            }

            var oldValue = _selectedItem;
            _selectedItem = value;

            // Update bindings, no broadcast
            RaisePropertyChanged(SelectedItemPropertyName);

            // Update bindings and broadcast change using GalaSoft.MvvmLight.Messenging
            //RaisePropertyChanged(SelectedItemPropertyName, oldValue, value, true);
        }
    }

    #endregion
}

3. Модель ItemView

открытый класс ItemViewModel: ViewModelBase {#region [Имя]

    /// <summary>
    /// The <see cref="Name" /> property's name.
    /// </summary>
    public const string NamePropertyName = "Name";

    private string _name = default(string);

    /// <summary>
    /// Gets the Name property.
    /// TODO Update documentation:
    /// Changes to that property's value raise the PropertyChanged event. 
    /// This property's value is broadcasted by the Messenger's default instance when it changes.
    /// </summary>
    public string Name {
        get {
            return _name;
        }

        set {
            if (_name == value) {
                return;
            }

            var oldValue = _name;
            _name = value;

            // Update bindings, no broadcast
            RaisePropertyChanged(NamePropertyName);

            // Update bindings and broadcast change using GalaSoft.MvvmLight.Messenging
            //RaisePropertyChanged(NamePropertyName, oldValue, value, true);
        }
    }

    #endregion

    #region [SubItems]

    /// <summary>
    /// The <see cref="SubItems" /> property's name.
    /// </summary>
    public const string SubItemsPropertyName = "SubItems";

    private ObservableCollection<ItemViewModel> _myProperty = new ObservableCollection<ItemViewModel>();

    /// <summary>
    /// Gets the SubItems property.
    /// TODO Update documentation:
    /// Changes to that property's value raise the PropertyChanged event. 
    /// This property's value is broadcasted by the Messenger's default instance when it changes.
    /// </summary>
    public ObservableCollection<ItemViewModel> SubItems {
        get {
            return _myProperty;
        }

        set {
            if (_myProperty == value) {
                return;
            }

            var oldValue = _myProperty;
            _myProperty = value;

            // Update bindings, no broadcast
            RaisePropertyChanged(SubItemsPropertyName);

            // Update bindings and broadcast change using GalaSoft.MvvmLight.Messenging
            //RaisePropertyChanged(SubItemsPropertyName, oldValue, value, true);
        }
    }

    #endregion
}

Редактировать 2

Шаблоны элемента управления Panorama можно найти здесь .

...