WPF 从 CodeBehind 更新 VievModel 绑定的 ListBox

问题描述 投票:0回答:1

我是 WPF/MVVM 的新手,我得到了两个带有两个按钮的列表框,一个用于将所选元素从左侧列表框复制到右侧列表框,然后使用第二个按钮返回。
启动时,左侧列表框正确填充了数据存储中的数据,当我选择一些元素并按下

btn_add_symbol_Click
按钮时,
AddSelectedSymbol
方法按预期执行,
OnPropertyChanged
以及
WidgetSymbolsSelected
的 getter (我想从右侧的 ListBox) 被调用,返回右侧更新的
CurrentWidget.Symbols
。问题是右侧的列表框
lst_SelectedSymbols
始终为空。这是怎么回事?谢谢。

XAML:

<ListBox Grid.Row="1" Grid.Column="0" ItemsSource="{Binding AvailableSymbols}" SelectionMode="Multiple" Name="lst_AvailableSymbols" />  
<ListBox Grid.Row="1" Grid.Column="2" ItemsSource="{Binding WidgetSymbolsSelected}" SelectionMode="Multiple" Name="lst_SelectedSymbols"/>

虚拟机:

public IEnumerable<string> AvailableSymbols
{
    get { return DataManager.AvailableSymbols; }
}

public IEnumerable<string> WidgetSymbolsSelected
{
    get { return CurrentWidget.Symbols; }
}

public void AddSelectedSymbol(string symbol)
{
    if (!CurrentWidget.Symbols.Contains(symbol)) {
        CurrentWidget.Symbols.Add(symbol);
        OnPropertyChanged("WidgetSymbolsSelected");
    }
}

隐藏代码:

private void btn_add_symbol_Click(object sender, RoutedEventArgs e)
{
    var ViewModel = (WidgetEditorViewModel)this.DataContext;
    foreach (var Item in lst_AvailableSymbols.SelectedItems)
    {
        ViewModel.AddSelectedSymbol(Item.ToString());
    }
}
c# wpf data-binding
1个回答
0
投票

实现示例,不保留初级排序

namespace Core2024.SO.DPZ.question79152344
{
    public class SomeTextItem
    {
        private string _title = string.Empty;
        private string _text = string.Empty;
        private string _description = string.Empty;

        public string Title { get => _title; set => _title = value ?? string.Empty; }
        public string Text { get => _text; set => _text = value ?? string.Empty; }
        public string Description { get => _description; set => _description = value ?? string.Empty; }
    }
}
using System.Collections.ObjectModel;
using Simplified; // This is the space with my implementation of INotifyPropertyChanged and ICommand interfaces. You can use your own implementations instead.

namespace Core2024.SO.DPZ.question79152344
{
    public class SomeTextViewModel
    {
        private const string data = "I'm brand new to WPF/MVVM and getting two ListBox wiht two buttons, one to copy selected elements from left listbox to the right one, and back with the second button.";
        private static IEnumerable<SomeTextItem> GetItems()
        {
            string[] split = data.Split();
            for (int i = 2; i < split.Length; i += 3)
            {
                yield return new SomeTextItem()
                {
                    Title = split[i - 2],
                    Text = split[i - 1],
                    Description = split[i]
                };
            }
        }
        public SomeTextViewModel()
        {
            AvailableSymbols = new ObservableCollection<SomeTextItem>(GetItems());
            WidgetSymbolsSelected = new();
            SelectTextItem = new RelayCommand<SomeTextItem>
            (
                item => { AvailableSymbols.Remove(item); WidgetSymbolsSelected.Add(item); },
                item => AvailableSymbols.Contains(item)
            );
            UnselectTextItem = new RelayCommand<SomeTextItem>
            (
                item => { WidgetSymbolsSelected.Remove(item); AvailableSymbols.Add(item); },
                item => WidgetSymbolsSelected.Contains(item)
            );
        }

        public ObservableCollection<SomeTextItem> AvailableSymbols { get; }
        public ObservableCollection<SomeTextItem> WidgetSymbolsSelected { get; }

        public RelayCommand SelectTextItem { get; }
        public RelayCommand UnselectTextItem { get; }
    }
}
<Window x:Class="Core2024.SO.DPZ.question79152344.WidgetSymbolsSelectedWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Core2024.SO.DPZ.question79152344"
        mc:Ignorable="d"
        Title="WidgetSymbolsSelectedWindow" Height="450" Width="800"
        DataContext="{DynamicResource vm}">
    <Window.Resources>
        <local:SomeTextViewModel x:Key="vm"/>
        <DataTemplate DataType="{x:Type local:SomeTextItem}">
            <TextBlock>
                <Run Text="{Binding Title}"/><Run Text=";"/>
                <Run Text="{Binding Text}"/><Run Text=";"/>
                <Run Text="{Binding Description}"/><Run Text=";"/>
            </TextBlock>
        </DataTemplate>
    </Window.Resources>
    <UniformGrid Columns="3">
        <ListBox x:Name="listBox" ItemsSource="{Binding AvailableSymbols}"/>
        <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
            <Button Content="-&gt;" Margin="10" Padding="15 5"
                    Command="{Binding SelectTextItem, Mode=OneWay}"
                    CommandParameter="{Binding SelectedItem, ElementName=listBox}"/>
            <Button Content="&lt;-" Margin="10" Padding="15 5"
                    Command="{Binding UnselectTextItem, Mode=OneWay}"
                    CommandParameter="{Binding SelectedItem, ElementName=listBox1}"/>
        </StackPanel>
        <ListBox x:Name="listBox1" ItemsSource="{Binding WidgetSymbolsSelected}"/>
    </UniformGrid>
</Window>

保留初级排序的实现示例

using Simplified;

namespace Core2024.SO.DPZ.question79152344
{
    public class SelectableSomeTextItem : BaseInpc
    {
        private string _title = string.Empty;
        private string _text = string.Empty;
        private string _description = string.Empty;
        private bool _isSelected;

        public string Title { get => _title; set => _title = value ?? string.Empty; }
        public string Text { get => _text; set => _text = value ?? string.Empty; }
        public string Description { get => _description; set => _description = value ?? string.Empty; }

        public bool IsSelected { get => _isSelected; set => Set(ref _isSelected, value); }
    }

}
using System.Collections.ObjectModel;
using Simplified; // This is the space with my implementation of INotifyPropertyChanged and ICommand interfaces. You can use your own implementations instead.

namespace Core2024.SO.DPZ.question79152344
{
    public class SelectableSomeTextViewModel
    {
        private const string data = "I'm brand new to WPF/MVVM and getting two ListBox wiht two buttons, one to copy selected elements from left listbox to the right one, and back with the second button.";
        private static IEnumerable<SelectableSomeTextItem> GetItems()
        {
            string[] split = data.Split();
            for (int i = 2; i < split.Length; i += 3)
            {
                yield return new SelectableSomeTextItem()
                {
                    Title = split[i - 2],
                    Text = split[i - 1],
                    Description = split[i]
                };
            }
        }
        public SelectableSomeTextViewModel()
        {
            AvailableSymbols = new ObservableCollection<SelectableSomeTextItem>(GetItems());
            SelectTextItem = new RelayCommand<SelectableSomeTextItem>
            (
                item => item.IsSelected = true,
                item => AvailableSymbols.Contains(item) && !item.IsSelected
            );
            UnselectTextItem = new RelayCommand<SelectableSomeTextItem>
            (
                item => item.IsSelected = false,
                item => AvailableSymbols.Contains(item) && item.IsSelected
            );
        }

        public ObservableCollection<SelectableSomeTextItem> AvailableSymbols { get; }

        public RelayCommand SelectTextItem { get; }
        public RelayCommand UnselectTextItem { get; }
    }
}
<Window x:Class="Core2024.SO.DPZ.question79152344.SelectableWidgetSymbolsSelectedWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Core2024.SO.DPZ.question79152344" xmlns:sys="clr-namespace:System;assembly=netstandard"
        mc:Ignorable="d"
        Title="SelectableWidgetSymbolsSelectedWindow" Height="450" Width="800"
        DataContext="{DynamicResource vm}">
    <Window.Resources>
        <local:SelectableSomeTextViewModel x:Key="vm"/>
        <DataTemplate DataType="{x:Type local:SelectableSomeTextItem}">
            <TextBlock>
                <Run Text="{Binding Title}"/><Run Text=";"/>
                <Run Text="{Binding Text}"/><Run Text=";"/>
                <Run Text="{Binding Description}"/><Run Text=";"/>
            </TextBlock>
        </DataTemplate>
        <CollectionViewSource x:Key="items.Unselected"
                              Source="{Binding AvailableSymbols}"
                              IsLiveFilteringRequested="True"
                              Filter="OnUnselectedFilter">
            <CollectionViewSource.LiveFilteringProperties>
                <sys:String>IsSelected</sys:String>
            </CollectionViewSource.LiveFilteringProperties>
        </CollectionViewSource>
        <CollectionViewSource x:Key="items.Selected"
                              Source="{Binding AvailableSymbols}"
                              IsLiveFilteringRequested="True"
                              Filter="OnSelectedFilter">
            <CollectionViewSource.LiveFilteringProperties>
                <sys:String>IsSelected</sys:String>
            </CollectionViewSource.LiveFilteringProperties>
        </CollectionViewSource>
    </Window.Resources>
    <UniformGrid Columns="3">
        <ListBox x:Name="listBox"
                 ItemsSource="{Binding Mode=OneWay, Source={StaticResource items.Unselected}}"/>
        <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
            <Button Content="-&gt;" Margin="10" Padding="15 5"
                    Command="{Binding SelectTextItem, Mode=OneWay}"
                    CommandParameter="{Binding SelectedItem, ElementName=listBox}"/>
            <Button Content="&lt;-" Margin="10" Padding="15 5"
                    Command="{Binding UnselectTextItem, Mode=OneWay}"
                    CommandParameter="{Binding SelectedItem, ElementName=listBox1}"/>
        </StackPanel>
        <ListBox x:Name="listBox1"
                 ItemsSource="{Binding Mode=OneWay, Source={StaticResource items.Selected}}"/>
    </UniformGrid>
    <x:Code>
        <![CDATA[
        private void OnUnselectedFilter(object sender, System.Windows.Data.FilterEventArgs e)
        {
            e.Accepted = !((SelectableSomeTextItem)e.Item).IsSelected;
        }

        private void OnSelectedFilter(object sender, System.Windows.Data.FilterEventArgs e)
        {
            e.Accepted = ((SelectableSomeTextItem)e.Item).IsSelected;
        }
        ]]>
    </x:Code>
</Window>

您可以从这里获取我的基类实现:我的基类实现示例:BaseInpc、RelayCommand、RelayCommandAsync、RelayCommand、RelayCommandAsync

© www.soinside.com 2019 - 2024. All rights reserved.