在更新为使用MVVM绑定到ViewModel的ListBox中获取SelectedItem或SelectedItems

时间:2019-08-15 18:39:10

标签: c# wpf mvvm

我正在使用带有Caliburn Micro和严格的MVVM模式的.NET Framework 4.7.2创建WPF网络扫描应用程序。我已经经历了所有与此类似的问题,但尚未找到解决方案。我不使用代码隐藏,因此我正在尝试做所有MVVM样式。

“我的列表框”最初是空的,并且向其中添加了项,直到完成扫描为止。此后,我尝试在ListBox中选择1个或多个项目,即使在视觉上可以选择多个项目,但我发现的问题是我无法使用SelectedItem属性将ListBox视图中的SelectedItem绑定。即我的ViewModel中的SelectedItem属性不会更新,并保持为null。

我希望我的SelectedItems集合随着选择更多项目而增加。

我尝试了以下方法:

Binding the IsSelected property of ListBoxItem to DataContext of Itemssource

Get ListBox SelectedItems

到目前为止,这些方法还没有奏效。

示例模型:

public class ExampleModel
{
    protected int _id;
    protected string _name;
    public ExampleModel()
    {

    }
    public ExampleModel(int _id, string _name)
    {
        this.Id = _id;
        this.Name = _name;
    }
    public int Id { get; set; }
    public string Name { get; set; }

    public override bool Equals(object obj)
    {
        return this.Name == Name && this.Id == Id;
    }

    public override int GetHashCode()
    {
        return Id.GetHashCode();
    }
}

ViewModel示例:

public class ExampleViewModel : Screen
{
    private IEventAggregator _events;
    public ExampleViewModel(IEventAggregator events)
    {
        // Initialize collection
        BindableCollection<ExampleModel> SelectedItems = new BindableCollection<ExampleModel>();
        _events = events;
    }

    private BindableCollection<ExampleModel> _selectedItems;

    public BindableCollection<ExampleModel> SelectedItems
    {
        get { return _selectedItems; }
        set
        {
           // SelectedItems remains NULL
            _selectedItems = value;
            NotifyOfPropertyChange(() => Items);
        }
    }

    private ExampleModel _selectedItem;

    public ExampleModel SelectedItem
    {
        get { return _selectedItem; }
        set
        {
            // CODE NOT UPDATING SELECTED ITEM VALUE!
            _selectedItem = value;
            NotifyOfPropertyChange(() => SelectedItem);
            NotifyOfPropertyChange(() => SelectedItems);

        }
    }

    // Initialize list
    private HashSet<ExampleModel> _exampleList = new HashSet<ExampleModel>();

    public HashSet<ExampleModel> ExampleList
    {
        get { return _exampleList; }
        set { _exampleList = value; }
    }

    private async Task AddItem(ExampleModel item)
    {
        // A task to asyncrhonously add unique items to list
        await Task.Run(() =>
        _exampleList.Add(item));
        Items = new BindableCollection<ExampleModel>(_exampleList);
        NotifyOfPropertyChange(() => Items);
    }

    private BindableCollection<ExampleModel> _items;

    public BindableCollection<ExampleModel> Items
    {
        get { return _items; }
        set
        {
            _items = value;
            NotifyOfPropertyChange(() => Items);
        }
    }

    // Begin adding items to list
    public async void Add()
    {
        for (int i = 0; i<10; i++)
        {
            // do something
            var item = new ExampleModel
            {
                Id = i + 1,
                Name = i.ToString()
            };
            await AddItem(item);
        }
    }

    // Button to start process
    public void Start()
    {
        Add();
    }

}

示例视图:

        <ScrollViewer ScrollViewer.VerticalScrollBarVisibility="Auto">
            <ListBox
                VirtualizingPanel.IsVirtualizing="True"
                VirtualizingPanel.ScrollUnit="Item"
                HorizontalContentAlignment="Stretch"
                ScrollViewer.IsDeferredScrollingEnabled="True"
                Margin="8 0 0 0"
                Grid.Column="1"
                ItemsSource="{Binding  Path= Items}"
                SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
                SelectionMode="Multiple"
                b:SelectedItemsBehavior.SelectedItems="{Binding SelectedItems, Mode=TwoWay}">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="*"/>
                                <ColumnDefinition Width="*"/>
                                <ColumnDefinition Width="*"/>
                            </Grid.ColumnDefinitions>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="auto"/>
                                <RowDefinition Height="auto"/>
                            </Grid.RowDefinitions>

                            <!-- Id -->
                            <TextBlock
                                Text="{Binding Id}"
                                Grid.Row="0"
                                Grid.Column="0"
                                />

                            <!-- Name -->
                            <TextBlock
                                Text="{Binding Name}"
                                Grid.Row="0"
                                Grid.Column="1"
                                Margin="10"
                                />              
                        </Grid>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>                    
            </ScrollViewer>

Selected Items Behavior类:

公共类SelectedItemsBehavior {

    public static readonly DependencyProperty SelectedItemsProperty =
        DependencyProperty.RegisterAttached("SelectedItems",

         typeof(INotifyCollectionChanged), typeof(SelectedItemsBehavior),
        new PropertyMetadata(default(IList), OnSelectedItemsChanged));

    public static void SetSelectedItems(DependencyObject d, INotifyCollectionChanged value)
    {
        d.SetValue(SelectedItemsProperty, value);
    }

    public static IList GetSelectedItems(DependencyObject element)
    {
        return (IList)element.GetValue(SelectedItemsProperty);
    }

    private static void OnSelectedItemsChanged(DependencyObject d,
                      DependencyPropertyChangedEventArgs e)
    {
        IList selectedItems = null;
        void CollectionChangedEventHandler(object sender, NotifyCollectionChangedEventArgs args)
        {
            if (args.OldItems != null)
                foreach (var item in args.OldItems)
                    if (selectedItems.Contains(item))
                        selectedItems.Remove(item);

            if (args.NewItems != null)
                foreach (var item in args.NewItems)
                    if (!selectedItems.Contains(item))
                        selectedItems.Add(item);
        };

        if (d is MultiSelector multiSelector)
        {
            selectedItems = multiSelector.SelectedItems;
            multiSelector.SelectionChanged += OnSelectionChanged;
        }
        if (d is ListBox listBox)
        {
            selectedItems = listBox.SelectedItems;
            listBox.SelectionMode = SelectionMode.Multiple;
            listBox.SelectionChanged += OnSelectionChanged;
        }
        if (selectedItems == null) return;

        if (e.OldValue is INotifyCollectionChanged)
            (e.OldValue as INotifyCollectionChanged).CollectionChanged
                           -= CollectionChangedEventHandler;
        if (e.NewValue is INotifyCollectionChanged)
            (e.NewValue as INotifyCollectionChanged).CollectionChanged
                           += CollectionChangedEventHandler;
    }

    private static void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        var s = sender as DependencyObject;
        if (!GetIsBusy(s))
        {
            SetIsBusy(s, true);
            var list = GetSelectedItems((DependencyObject)sender);
            foreach (var item in e.RemovedItems)
                if (list.Contains(item)) list.Remove(item);
            foreach (var item in e.AddedItems)
                if (!list.Contains(item)) list.Add(item);
            SetIsBusy(s, false);
        }
    }

    private static readonly DependencyProperty IsBusyProperty =
        DependencyProperty.RegisterAttached("IsBusy", typeof(bool),

              typeof(SelectedItemsBehavior), new PropertyMetadata(default(bool)));

    private static void SetIsBusy(DependencyObject element, bool value)
    {
        element.SetValue(IsBusyProperty, value);
    }

    private static bool GetIsBusy(DependencyObject element)
    {
        return (bool)element.GetValue(IsBusyProperty);
    }
}

我希望可以填充SelectedItems集合,但输出仍为null。 我希望选择任何项目时,SelectedItem的值都会更新,但会为空。

0 个答案:

没有答案