将所选项写入ObservableCollection

时间:2015-12-04 07:47:43

标签: c# wpf mvvm

我的视图中有一个简单的ListView:

<ListView x:Name="ObjectListView" HorizontalAlignment="Left" Height="105" Margin="253,268,0,0" VerticalAlignment="Top" Width="163" SelectionChanged="ObjectListView_SelectionChanged">
     <TextBox Width="100"/>
     <Button Width="100" Content="Test"/>
     <Label Width="100" Content="Label"/>
</ListView>

在我的ViewModel中,我有一个ObservableCollection,它做了一些(对于这个问题无关紧要)的事情:

public ObservableCollection<Object> ObjectCollection
    {
        get { return _conversionCollection; }
        set
        {
            if (_conversionCollection != value)
            {
                _conversionCollection = value;
                RaisePropertyChanged("ObjectList");
            }
        }
    }

最终,这些对象自然落在模型中(编辑:通过RaisePropertyChanged和一些函数的帮助),但我的问题是View和ViewModel之间的连接。

目前,我已经解决了这个问题(在View的代码隐藏中):

public MainWindow()
{
    InitializeComponent();
    _viewModel = (RibbonViewModel)base.DataContext;
}

private void ObjectListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        _viewModel.ObjectCollection.Clear();
        foreach(Object item in ObjectListView.SelectedItems)
        {
            _viewModel.ObjectCollection.Add(item);
        }
    }

这并不是太美丽,所以我想要做得恰到好处。

4 个答案:

答案 0 :(得分:2)

您只需要将ListView SelectedItems绑定到ObservableCollection,这样您的收藏就会使用绑定自动更新。实际上,您不需要将事件添加到您的代码中。

<ListView x:Name="ObjectListView" HorizontalAlignment="Left" Height="105" Margin="253,268,0,0" VerticalAlignment="Top" Width="163" SelectedItems="{Binding Path=ObjectCollection}">
     <TextBox Width="100"/>
     <Button Width="100" Content="Test"/>
     <Label Width="100" Content="Label"/>
</ListView>

修改

要实现您想要的效果,请尝试使用Interaction triggers,如下所示

将以下xmlns添加到您的xaml

xmlns:i="http://schemas.microsoft.com/expression//2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"

不要忘记添加该引用:

  

Microsoft.Expression.Interactions System.Windows.Interactivity

<ListView x:Name="ObjectListView" HorizontalAlignment="Left" Height="105" Margin="253,268,0,0" VerticalAlignment="Top" Width="163">
         <TextBox Width="100"/>
         <Button Width="100" Content="Test"/>
         <Label Width="100" Content="Label"/>
         <i:Interaction.Triggers>
            <i:EventTrigger EventName="SelectionChanged">
            <ei:ChangePropertyAction TargetObject="{Binding Mode=OneWay}" PropertyName="SelectedItems" Value="{Binding Path=SelectedItems,     ElementName=ObjectListView}"/>
         </i:EventTrigger>
        </i:Interaction.Triggers>
    </ListView>

视图模型

public System.Collections.IList SelectedItems {
    get {
      return ObjectCollection;
    }
    set {
      ObjectCollection.Clear();
      foreach (var model in value) {
        ObjectCollection.Add(model);
      }
    }
  }

答案 1 :(得分:1)

基本上,您需要数据绑定 ViewModel.ObjectCollectionListView.SelectedItems

默认情况下,WPF控件不支持此功能,但您可以扩展控件以支持此功能。扩展控制的一种方法是行为。有两种类型的行为:

  1. System.Windows.Interactivity Behaviors。
  2. 作为附加属性实现的行为。

    <ListView my:ListViewExtension.SelectedItems="{Binding ObjectCollection}" />
    
  3. 我决定使用秒。基本上你创建自定义附加属性,在DependencyPropertyChanged回调中,你可以通过附加到元素'eventhandlers来“注入”任何代码到框架元素。

    public static class ListViewExtentions
    {
        public static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.RegisterAttached(
            "SelectedItems", typeof (IList), typeof (ListViewExtentions), new PropertyMetadata(SelectedItems_PropertyChanged));
        public static void SetSelectedItems(DependencyObject element, IList value)
        {
            element.SetValue(SelectedItemsProperty, value);
        }
        public static IList GetSelectedItems(DependencyObject element)
        {
            return (IList)element.GetValue(SelectedItemsProperty);
        }
    
    
        private static void SelectedItems_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var listView = (ListView) d;
            SynchronizeCollections(listView.SelectedItems, (IList)e.NewValue);
    
            listView.SelectionChanged += (sender, args) =>
            {
                var listviewSelectedItems = ((ListView) sender).SelectedItems;
                var viewmodelCollection = GetSelectedItems((ListView) sender);
                SynchronizeCollections(listviewSelectedItems, viewmodelCollection);
            };
        }
    
        private static void SynchronizeCollections(IList source, IList target)
        {
            var oldItems = target.OfType<object>().Except(source.OfType<object>()).ToArray();
            var newItems = source.OfType<object>().Except(target.OfType<object>()).ToArray();
    
            foreach (var oldItem in oldItems) target.Remove(oldItem);
            foreach (var newItem in newItems) target.Add(newItem);
        }
    }
    

    您可以使用propa代码段生成附加属性

    提示:我建议您将ViewModel.ObjectCollection重命名为ViewModel.SelectedItems,因为现在它具有误导性。

答案 2 :(得分:0)

也许这个例子可以帮到你。

<Grid>
    <ListView  HorizontalAlignment="Left" VerticalAlignment="Top" ItemsSource="{Binding ObjectCollection}" SelectedItem="{Binding SelectedItem}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition/>
                        <ColumnDefinition/>
                        <ColumnDefinition/>
                    </Grid.ColumnDefinitions>
                    <TextBox Width="100" Grid.Column="0" Text="{Binding Text}"/>
                    <Button Width="100" Content="Test" Grid.Column="1"/>
                    <Label Width="100" Grid.Column="2" Content="{Binding Label}"/>
                </Grid>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</Grid>

代码:

namespace WpfApplication
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new ViewModel();
    }
}

public class Obj : INotifyPropertyChanged
{
    public string Text { get; set; }

    private string label;
    public string Label
    {
        get
        {
            return this.label;
        }

        set
        {
            this.label = value;
            this.RaisePropertyChaged("Label");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void RaisePropertyChaged(string info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }
}

public class ViewModel
{
    private Obj selectedItem;
    public Obj SelectedItem
    {
        get
        {
            return this.selectedItem;
        }

        set
        {
            this.selectedItem = value;
            this.selectedItem.Label = value.Text;
        }
    }
    public ObservableCollection<Obj> ObjectCollection { get; set; }
    public ViewModel()
    {
        ObjectCollection = new ObservableCollection<Obj>();
        ObjectCollection.Add(new Obj { Text = "First" });
        ObjectCollection.Add(new Obj { Text = "Second" });
        ObjectCollection.Add(new Obj { Text = "Third" });
    }
}
}

答案 3 :(得分:-1)

<ListView x:Name="Lst" SelectedItem="{Binding ChosenItem}"> ... </ListView>

这将在ChosenItem DP中添加所选项目,在其设置器中,您只需将项目添加到集合中即可。

private static void ChosenItemPropertyCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {            
            controls.Add(e.NewValue.ToString());
        }