将 eventtocommand 操作动态添加到列表框

发布于 2024-11-17 06:17:26 字数 1129 浏览 6 评论 0原文

我有一个带有

命名空间的页面:

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 代码...

如何做我在运行时在视图后面的代码中执行上述操作。

另外,我想将动态生成的列表框的数据上下文分配给与当前绑定到我的视图的视图模型不同的视图模型。

基本上,我有一个全景图,每个全景项目都是动态创建的,每个全景项目都有一个列表框,该列表框将通过中继命令绑定到视图模型

I have a page with

namespaces:

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 at design time:

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

In the code, I am generating multiple listboxes at run time and would like to be able to bind to a relaycommand on the viewmode like the above xaml code shown above...

How do I do the above at run time in the code behind of the view.

Also, I would like to assign the datacontext for the dynamically generated listboxes to different view models than the one currently bound to my view.

Basically, I have a panaroma and with each panaroma items being created dynamically with each panaroma item having a listbox that will be bound to a viewmodel with relaycommands

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

大海や 2024-11-24 06:17:26

注意:另请参阅相关发布

本文介绍了如何从代码隐藏中附加行为。

但是,我坚决不建议您走这条路,除非您有令人信服的需要这样做。如果您在 ViewModel 中使用此方法,您将失去所有可测试性,因为它会生成与 View 高度耦合的 ViewModel,并且没有它,事实就无法生存。 (旁注:因此,将事件参数返回到 ViewModel 也不是一个好习惯,使用 CommandParameter 返回 >DataContext(如果需要)。

通常,您可以使用 MVVM 以另一种方式归档您的目标,本文的其余部分对此进行了描述。

首先,您不需要使用Command来获取选定的属性,也不需要获取该属性已更改的通知。通常的模式是将列表框的 SelectedItem 绑定到 ViewModel 中的属性。现在,您可以使用 PropertyChanged 事件来跟踪此属性何时发生更改。

其次,使用模板生成列表框并设置其样式。当您只需要在选择项目时显示它们时,请使用 BooleanToVisibility (示例请参见此处转换器,并将子列表框的 Visibility 属性绑定到您的 ViewModel 上的属性转换器(不是我的示例)。

该示例创建一个 ListBox,其 ItemsSource 绑定到 ViewModel 的 Items 属性。它还创建一个 ContentControl<。 /code> 将其 DataContext 绑定到 ViewModelSelectedItem,然后 ContentControl 再次包含 。代码>列表框其中DataContext 绑定到 ItemViewModelSubItem 属性。 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 [Name]

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

Edit 2

Panorama 控件的模板可以在 此处

Note: See also related post.

This article describes how you can attach behaviours from code behind.

However, I firmly would not advise you to go down this route unless you have a compelling need to do so. If you use this approach in your ViewModel, you will loose all testability as it generates a ViewModel that is highly coupled to the View, and in fact cannot live without it. (Side note: for this reason it is also not good practise to return the event args to the ViewModel use CommandParameter instead to return the DataContext if needed).

Normally you can archive your goal using MVVM in another manner, and the rest of the post describes this.

First, you do not need to use a Command to get the selected property, nor to get the notification that this property has changed. The usual pattern for this is that you bind the SelectedItem of your list box to a property in your ViewModel. Now you can use the PropertyChanged event to track when this property changed.

Second, use templates to generate and style your listboxes. When you need to only show them when the item is selected use a BooleanToVisibility (Sample see here converter and bind the sub-listboxes' Visibility property to a property on your ViewModel using the converter (not my the sample).

The sample creates a ListBox that has its ItemsSource bound to the Items property of the ViewModel. It further creates a ContentControl that has its DataContext bound to the SelectedItem of the ViewModel. The ContentControl then contains again a ListBox where the DataContext is bound to the SubItem property of the ItemViewModel. The MainViewModel generates test data to be shown at design time and run time.

The rest of the post shows an sample:

1. XAML of main page (except):

        <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. The Main View Model

    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. The ItemView Model

public class ItemViewModel : ViewModelBase
{
#region [Name]

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

Edit 2

The templating of the Panorama control can be found here.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文