【问题标题】:How to get selected listbox item to update another listbox?如何获取选定的列表框项目以更新另一个列表框?
【发布时间】:2016-01-15 20:47:03
【问题描述】:

我对 wpf 和 mvvm 很陌生,我希望这有意义...

我有一个 CheckBox 项目的 ListBox。当我选中或取消选中一个项目时,我想知道如何触发一个事件或任何能让我能够将所选项目文本添加到不同 ListBox 的方法。

这是我迄今为止所做的:

XAML:

<ListBox ItemsSource="{Binding Target}" IsEnabled="{Binding IsControlEnabled}">
     <ListBox.ItemTemplate>
          <DataTemplate>
                <CheckBox Content="{Binding TitleName}" IsChecked="{Binding IsChecked}" />
          </DataTemplate>
     </ListBox.ItemTemplate>
</ListBox>

主视图模型类:

private ObservableCollection<CheckServerItem> _target = new ObservableCollection<CheckServerItem>();

处理复选框事件的小类:

public class CheckServerItem : ViewModelBase
{
    private bool _isChecked { get; set; }
    private string _Title { get; set; }

    public bool IsChecked
    {
        get { return _isChecked; }
        set
        {
            _isChecked = value;
            RaisePropertyChanged("IsChecked");
        }
    }
    public string TitleName
    {
        get { return _Title; }
        set
        {
            _Title = value;
            RaisePropertyChanged("TitleName");
        }
    }
}

检查由小类正确处理,但我不知道如何让该类调用 Main ViewModel 类中管理其他 ListBox 的方法或我应该调用的方法。

感谢您的帮助!

【问题讨论】:

  • 要走的一条路是在视图模型中添加事件以监听复选框
  • 另一个 ListBox 也使用相同的 MainViewModel ?
  • @SamTheDev,另一个列表框在 MainViewModel 中。

标签: c# wpf mvvm


【解决方案1】:

根据Filippo Vigani的回答,如果只用鼠标选中/取消选中复选框,您也可以执行以下操作,

        <ListBox.ItemTemplate>
            <DataTemplate>
                <CheckBox Content="{Binding TitleName}"
                          IsChecked="{Binding IsChecked}"
                          Command="{Binding DataContext.SelectionChangedCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"
                          CommandParameter="{Binding}" />
            </DataTemplate>
        </ListBox.ItemTemplate>

【讨论】:

  • 这个选项看起来最有趣,但我不确定我要绑定到 MainViewModel 中的哪个属性。你能帮忙解决一下@shahjahan 吗?
【解决方案2】:

我建议将其他 ListBox 的 ItemsSource 绑定到相同的 ObservableCollection,然后使用 Converter 来获取所选项目。然后,您根本不必纠结于附加和分离事件处理程序。转换器将是:

[ValueConversion(typeof(object), typeof(object))]
public class IsCheckedConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        ObservableCollection<CheckServerItem> result = new ObservableCollection<CheckServerItem>();
        foreach(CheckServerItem item in (value as ObservableCollection<CheckServerItem>))
        {
            if (item.IsChecked)
            {
                result.Add(item);
            }
        }
        return result;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return Binding.DoNothing;
    }
}

您需要将转换器放在应用程序或窗口的资源部分,以便您可以在列表框中使用它:

<this:IsCheckedConverter x:Key="MyIsCheckedConverter" />

然后您对其他 ListBox 的 ItemsSource 的绑定将如下所示:

<ListBox ItemsSource="{Binding Target, Converter={StaticResource MyIsCheckedConverter}}>

【讨论】:

  • 我个人不会这样做,因为这种类型的过滤是您想要进行单元测试的主要候选者,或者至少能够在您的VM 并且能够在调试器中单步执行而不会妨碍视图。就我个人而言,我会在主视图模型中添加第二个集合,并在其中进行过滤以响应 IsChecked 属性的变化。
  • 如果这个其他列表框满足某种功能要求(即进行了进一步的选择并且对辅助选择进行了某些操作),我只会向 VM 添加第二个集合。我想象这个辅助列表框只是在视图中服务于一个目的,这只是向用户说明选择了哪些项目。我以前一直走这条路,对我来说,尝试同步列表和注册/注销事件处理程序(并引入可能的内存泄漏)以满足非功能性需求似乎不值得
【解决方案3】:

我建议使用 ICommand 并使用 AttachedCommandBehaviour 将其绑定到 CheckBox 的 Checked RoutedEvent(您可以在 nuget 上获得它):

Install-Package AttachedCommandBehavior

xaml 看起来像这样:

...
xmlns:acb="clr-namespace:AttachedCommandBehavior;assembly=AttachedCommandBehavior"
...
<ListBox ItemsSource="{Binding Target}"
         IsEnabled="{Binding IsControlEnabled}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <CheckBox Content="{Binding TitleName}"
                      IsChecked="{Binding IsChecked}">
                <acb:CommandBehaviorCollection.Behaviors>
                    <acb:BehaviorBinding Event="Checked"
                                         Command="{Binding DataContext.SelectionChangedCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"
                                         CommandParameter="{Binding}" />
                    <acb:BehaviorBinding Event="Unchecked"
                                         Command="{Binding DataContext.SelectionChangedCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"
                                         CommandParameter="{Binding}" />
                </acb:CommandBehaviorCollection.Behaviors>
            </CheckBox>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

然后在您的 ViewModel 中,您将拥有一个处理检查/取消检查事件的命令。您可以将 Prism 用于实现称为 DelegateCommand 的 ICommand 的类,您可以从 nuget 获取它:

Install-Package Prism.Core

您的视图模型中的命令可能类似于:

private DelegateCommand<CheckServerItem> selectionChangedCommand;

    public DelegateCommand<CheckServerItem> SelectionChangedCommand
    {
        get
        {
            return this.selectionChangedCommand ?? (this.selectionChangedCommand = new DelegateCommand<CheckServerItem>((x) =>
            {
                if (x.IsChecked)
                {
                    MyOtherList.Add(x);
                } else
                {
                    MyOtherList.Remove(x);
                }
            }));
        }
    }

【讨论】:

    猜你喜欢
    • 2014-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-21
    • 1970-01-01
    相关资源
    最近更新 更多