C# 我怎样才能插入一个“;选择全部";组合框顶部的项及其项资源集?

C# 我怎样才能插入一个“;选择全部";组合框顶部的项及其项资源集?,c#,wpf,xaml,mvvm,combobox,C#,Wpf,Xaml,Mvvm,Combobox,我有一个组合框,其itemsource设置为IList的MyClass对象。我覆盖了组合框的项目模板,在项目旁边显示一个复选框。我想在顶部有一个项目,上面写着“全选”,当用户选中复选框时,代码会选中所有复选框。我的问题是,MVVM是如何做到这一点的 我不想将单独的MyClass对象添加到IList。这似乎会涉及太多视图和模型的耦合。有没有一种方法可以直接在XAML代码中添加一个项,并给它一个检查所有复选框的命令 我现在的组合框是: <ComboBox ItemsSource="{Bindi

我有一个
组合框
,其
itemsource
设置为
IList
MyClass
对象。我覆盖了
组合框
项目模板
,在项目旁边显示一个
复选框
。我想在顶部有一个项目,上面写着“全选”,当用户选中
复选框时,代码会选中所有
复选框。我的问题是,MVVM是如何做到这一点的

我不想将单独的
MyClass
对象添加到
IList
。这似乎会涉及太多视图和模型的耦合。有没有一种方法可以直接在XAML代码中添加一个项,并给它一个检查所有
复选框的
命令

我现在的
组合框是:

<ComboBox ItemsSource="{Binding MyList}" Width="200">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <CheckBox Content="{Binding Name}" IsChecked="{Binding Selected}" />
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>
编辑:我找到了一种在XAML代码中使用添加项到集合的方法。当用户选中“全选”项的复选框时,我仍然需要一种运行代码的方法。要仅添加项目,代码如下:

<ComboBox Width="200">

    <ComboBox.Resources>
        <CollectionViewSource x:Key="comboBoxSource" Source="{Binding Path=MyList}" />
    </ComboBox.Resources>

    <ComboBox.ItemsSource>
        <CompositeCollection>
            <local:MyClass Name="Select All" Selected="False">
            </local:MyClass>
            <CollectionContainer Collection="{Binding Source={StaticResource comboBoxSource}}" />
        </CompositeCollection>
    </ComboBox.ItemsSource>

    <ComboBox.ItemTemplate>
        <DataTemplate>
            <CheckBox Content="{Binding Name}" IsChecked="{Binding Selected}" />
        </DataTemplate>
    </ComboBox.ItemTemplate>

</ComboBox>

选择项目时必须注册事件,选择项目时,请检查所选项目是否为第一个项目(使用索引),然后将选择更改为“需要什么”。
(这里没有IDE,很抱歉没有代码)。

我个人只需修改复选框的模板,并使用Click handler在那里添加自定义复选框,没有什么太花哨的东西,很容易理解

从中可以修改此零件:

<ScrollViewer Margin="4,6,4,6"
                                SnapsToDevicePixels="True">
                    <StackPanel IsItemsHost="True"
                                KeyboardNavigation.DirectionalNavigation="Contained" />
</ScrollViewer>

并将自定义对象添加到IList。这将很好地工作,没有任何废话,您的viewmodel对view没有概念,+它是可测试的。对每个人来说都是双赢的

无论何时按下“全选”按钮,您都可以调用操作,绑定到itemssource,在整个集合中枚举,并将选定值设置为true。此解决方案需要混合界面

 <local:MyClass Name="Select All" Selected="False">
          <i:Interaction.Triggers>
                <ic:DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Selected}" Value="True">
                            <local:SelectAll TargetObject="{Binding RelativeSource={RelativeSource AncestorType=ComboBox}, Path=ItemsSource}"/>
                </ic:DataTrigger>
           </i:Interaction.Triggers>
</local:MyClass>

然后创建类SelectAll,如下所示

public class SelectAll : TargetedTriggerAction<List<MyClass>>
{
    protected override void Invoke(object parameter)
    {
        if (Target is List<MyClass>)
            foreach (var elem in (List<MyClass>)Target)
                elem.Selected = true;
    }
}
public类SelectAll:TargetedTriggerAction
{
受保护的覆盖无效调用(对象参数)
{
如果(目标是列表)
foreach(var elem in(列表)目标)
elem.Selected=true;
}
}

我想出了一种使用一些简单概念的方法

我的第一个问题是,我想在列表的顶部添加一个“全选”项目,而不是实际将一个项目添加到数据库
IList
。我编辑了我的原始帖子,以表明我可以使用
CompositeCollection
来完成这项工作。我使“全选”数据绑定对象成为
MyClass
的子类,并将该类称为
MyClassSelectAll
。下面将对此进行详细介绍

我的第二个问题是,我需要处理
复选框。与常规
MyClass
项目不同,单击“全选”项目的
事件。我给每个
复选框
一个
命令
,我可以用它来检查
复选框
。为此,我需要对用户单击的
IList
复选框
进行引用(更具体地说,是绑定到该
复选框的
MyClass
对象)

我发现解决第二个问题的一种方法是将
复选框.CommandParameter
设置为包含这两个对象的
多绑定。在
命令.Execute(object)
方法中,我可以轻松地检查当前的
MyClass
是否是
MyClassSelectAll
,如果是,我可以遍历
IList
列表(不包含“全选”项),并适当地设置“Selected”属性

以下是我的相关XAML代码:

<Grid.Resources>
    <local:MyCommand x:Key="kMyCommand" />
    <local:MyConverter x:Key="kConv" />
</Grid.Resources>

<ComboBox Width="200">

    <ComboBox.Resources>
        <CollectionViewSource x:Key="comboBoxSource" Source="{Binding Path=MyList}" />
    </ComboBox.Resources>

    <ComboBox.ItemsSource>
        <CompositeCollection>
            <local:MyClassSelectAll Name="Select All" Selected="False" />
            <CollectionContainer Collection="{Binding 
                Source={StaticResource comboBoxSource}}" />
        </CompositeCollection>
    </ComboBox.ItemsSource>

    <ComboBox.ItemTemplate>
        <DataTemplate>
            <CheckBox Content="{Binding Name}" 
                IsChecked="{Binding Selected}" 
                Command="{StaticResource kMyCommand}">
                <CheckBox.CommandParameter>
                    <MultiBinding Converter="{StaticResource kConv}">
                        <Binding RelativeSource="{RelativeSource 
                            FindAncestor, AncestorType={x:Type Window}}" 
                            Path="DataContext.MyList" />
                        <Binding Path="." />
                    </MultiBinding>
                </CheckBox.CommandParameter>
            </CheckBox>
        </DataTemplate>
    </ComboBox.ItemTemplate>

</ComboBox>
我用来传递
MyList
CurrentItem
引用的
MyCommandArgs
类是一个简单的容器类,所以我不会在这里发布它

MyClassSelectAll
是最简单的;它唯一的任务是将“selectall”
MyClass
对象标记为selectall对象

class MyClassSelectAll : MyClass
{
}
最后是处理单击事件的
MyCommand
对象

class MyCommand : ICommand
{
    public bool CanExecute(object parameter)
    {
        return true;
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        var mylist = parameter as MyCommandArgs;
        if (mylist != null && mylist.CurrentItem is MyClassSelectAll)
        {
            foreach (var item in mylist.MyList)
            {
                item.Selected = mylist.CurrentItem.Selected;
            }
        }
    }
}

谢谢大家。我真的被困在这上面了。似乎很多时候,当我在WPF中执行某些操作时遇到问题,解决方法是使用
转换器

这听起来像WinForms的方法。这将导致紧密耦合,正如我在上面提到的在MyList顶部插入项目时所提到的。如果您想使事情复杂化,理论上,您可以创建新的MyClassSelectAll类,并将其添加到CompositeCollection中,为特定类型创建新的DataTemplate,并钩住CheckBoxs CHecked事件。最后,我做了类似于您建议的事情。我使用了一个命令而不是Checked事件。我不确定如何修改复选框模板,我不想更改我的
MyClass
class。谢谢你的帮助。
class MyConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, 
        object parameter, System.Globalization.CultureInfo culture)
    {
        MyCommandArgs result = new MyCommandArgs()
        {
            MyList = values[0] as IList<MyClass>,
            CurrentItem = values[1] as MyClass
        };
        return result;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, 
        object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
class MyClassSelectAll : MyClass
{
}
class MyCommand : ICommand
{
    public bool CanExecute(object parameter)
    {
        return true;
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        var mylist = parameter as MyCommandArgs;
        if (mylist != null && mylist.CurrentItem is MyClassSelectAll)
        {
            foreach (var item in mylist.MyList)
            {
                item.Selected = mylist.CurrentItem.Selected;
            }
        }
    }
}