RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 681003
Accepted
Андрей NOP
Андрей NOP
Asked:2020-06-19 17:18:36 +0000 UTC2020-06-19 17:18:36 +0000 UTC 2020-06-19 17:18:36 +0000 UTC

WPF - 用于集合的 ConvertBack

  • 772

有一个所有交易对手的列表Contractors,有一个合作伙伴列表Partners,第二个列表是第一个列表的子集,这两个属性都可用VM。

In Viewis ItemsControlwithCheckBox'ами其中包含交易对手列表:

<ItemsControl ItemsSource="{Binding Contractors}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <CheckBox Content="{Binding Name}">
                ...
            </CheckBox>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

我现在需要选中所有合作伙伴的复选框:

                <CheckBox.IsChecked>
                    <MultiBinding Converter="{StaticResource CheckPartnersConverter}">
                        <Binding Mode="OneWay"/>
                        <Binding Path="DataContext.Partners"
                                 RelativeSource="{RelativeSource FindAncestor, AncestorType=ItemsControl}"/>
                    </MultiBinding>
                </CheckBox.IsChecked>

在转换器中实现了该方法Convert:

class CheckPartnersConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        if (values[1] is List<Contractor> partners && values[0] is Contractor c)
            return partners.Contains(c);
        return false;
    }

好的,这似乎有效。

现在如何实现反向转换,甚至有可能实现它?

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        var res = new object[]
        {
            Binding.DoNothing,
            Binding.DoNothing
        };
        return res;
    }
}

如果这不可能,我准备放弃带有复选框的演示文稿并替换它,例如,ListBox只选择合作伙伴,但击败SelectionMode="Multiple"也没有问题SelectedItems

c#
  • 3 3 个回答
  • 10 Views

3 个回答

  • Voted
  1. sp7
    2020-06-19T19:48:16Z2020-06-19T19:48:16Z

    好了,说到这里,其实问题可以有几种解决方法,其中一种是用EventTrigger,还有一种是用 (attached property和behavior) ,但其实这些解决方法的本质是差不多的。

    XAML编码:

    <ListBox Name="MyListBox"
                 Grid.Row="0"
                 DisplayMemberPath="Name"
                 ItemsSource="{Binding Users}"
                 SelectionMode="Multiple">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="SelectionChanged">
                    <i:InvokeCommandAction Command="{Binding SelectedItemChangedCommand}"
                                           CommandParameter="{Binding ElementName=MyListBox, Path=SelectedItems}" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
    </ListBox>
    

    接下来,ViewModel创建一个命令:

    public Command<IList> SelectedItemChangedCommand { get; set; }
    

    作为此命令的参数Action'a,将有选定的条目

    SelectedItemChangedCommand = new Command<IList>(items => 
    {
        foreach (User item in items)
        {
        }
    });
    

    PS 要与您一起工作EventTrigger,InvokeCommandAction您必须拥有System.Windows.Interactivity.

    此命名空间的XAML连接如下所示:

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

    为了使对属性的绑定SelectedItems在两个方向上起作用,即 为了能够从 设置此属性VM,您可以使用attached property. 使用时,EventTrigger不再需要它。

    public class SelectedItemsAttachedProperty
    {
        public static IList GetSelectedItems(ListBox obj)
        {
            return (IList)obj.GetValue(SelectedItemsProperty);
        }
    
        public static void SetSelectedItems(ListBox obj, IList value)
        {
            obj.SetValue(SelectedItemsProperty, value);
        }
    
        public static readonly DependencyProperty
            SelectedItemsProperty =
                DependencyProperty.RegisterAttached(
                    "SelectedItems",
                    typeof(IList),
                    typeof(SelectedItemsAttachedProperty),
                    new PropertyMetadata(null,
                        SelectedItemsChanged));
    
        private static void SelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var lb = d as ListBox;
    
            if(lb == null)
                return;
    
            IList coll = e.NewValue as IList;
    
            if (coll is INotifyCollectionChanged)
            {
                (coll as INotifyCollectionChanged)
                    .CollectionChanged += (s, collArgs) =>
                    {
                        if (collArgs.OldItems != null)
                            foreach (var item in collArgs.OldItems)
                                lb.SelectedItems.Remove(item);
                        if (null != collArgs.NewItems)
                            foreach (var item in collArgs.NewItems)
                                lb.SelectedItems.Add(item);
                    };
            }
    
            if (coll != null)
            {
                if (coll.Count > 0)
                {
                    lb.SelectedItems.Clear();
                    foreach (var item in coll)
                        lb.SelectedItems.Add(item);
                }
    
                lb.SelectionChanged += (s, lbArgs) =>
                {
                    if (null != lbArgs.RemovedItems)
                        foreach (var item in lbArgs.RemovedItems)
                            coll.Remove(item);
                    if (null != lbArgs.AddedItems)
                        foreach (var item in lbArgs.AddedItems)
                            coll.Add(item);
                };
            }
        }
    }
    

    XAML

    <ListBox Grid.Row="0"
           wpfApp:SelectedItemsAttachedProperty.SelectedItems="{Binding SelectedItems}"
           DisplayMemberPath="Name"
           ItemsSource="{Binding Data}"
           SelectionMode="Multiple" />
    

    因此,VM您可以向SelectedItems绑定到我们的 的 中添加元素AttachedProperty。

    • 1
  2. Best Answer
    VladD
    2020-06-20T04:16:46Z2020-06-20T04:16:46Z

    我认为你是在为自己找麻烦。

    看,您的业务逻辑想要从承包商中选择合作伙伴。这是业务逻辑的重要组成部分,这意味着不后悔为它创建一个单独的 VM 类是有道理的:

    class MaybePartner : NotifyPropertyChangedImpl
    {
        public Contractor Contractor { get; }
    
        bool isPartner;
        public bool IsPartner
        {
            get => isPartner;
            set
            {
                if (Set(ref isPartner, value))
                {
                    // тут можно включить контрагента в список или исключить его
                }
            }
        }
    
        public MaybePartner(Contractor c, bool isInitiallyPartner)
        {
            Contractor = c;
            isPartner = isInitiallyPartner;
        }
    }
    

    现在您的任务很简单:当您输入业务逻辑的这一部分时,您创建一个 的列表MaybePartner,并简单地绑定为

    <ItemsControl ItemsSource="{Binding MaybePartners}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <CheckBox Content="{Binding Contractor.Name}" IsChecked="{Binding IsPartner}"/>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
    

    似乎就是一切。

    • 1
  3. Андрей NOP
    2020-06-19T17:45:08Z2020-06-19T17:45:08Z

    像这样改变它:

    <ListBox ItemsSource="{Binding Contractors}"
             DisplayMemberPath="Name" SelectionMode="Multiple"
             DataContextChanged="OnDataContextChanged"/>
    

    事件处理程序代码:

    private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        var listBox = sender as ListBox;
        if (e.OldValue is Provider oldProv)
            oldProv.Partners = listBox.SelectedItems.Cast<Contractor>().ToList();
        if (e.NewValue is Provider newProv)
        {
            listBox.SelectedItems.Clear();
            foreach (var c in newProv.Partners)
                listBox.SelectedItems.Add(c);
        }
    }
    

    原则上,一切正常,这个解决方案适合我。谁会建议如何使用复选框使其适应视图。

    • 0

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    Python 3.6 - 安装 MySQL (Windows)

    • 1 个回答
  • Marko Smith

    C++ 编写程序“计算单个岛屿”。填充一个二维数组 12x12 0 和 1

    • 2 个回答
  • Marko Smith

    返回指针的函数

    • 1 个回答
  • Marko Smith

    我使用 django 管理面板添加图像,但它没有显示

    • 1 个回答
  • Marko Smith

    这些条目是什么意思,它们的完整等效项是什么样的

    • 2 个回答
  • Marko Smith

    浏览器仍然缓存文件数据

    • 1 个回答
  • Marko Smith

    在 Excel VBA 中激活工作表的问题

    • 3 个回答
  • Marko Smith

    为什么内置类型中包含复数而小数不包含?

    • 2 个回答
  • Marko Smith

    获得唯一途径

    • 3 个回答
  • Marko Smith

    告诉我一个像幻灯片一样创建滚动的库

    • 1 个回答
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Алексей Шиманский 如何以及通过什么方式来查找 Javascript 代码中的错误? 2020-08-03 00:21:37 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    user207618 Codegolf——组合选择算法的实现 2020-10-23 18:46:29 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5