2

我正在使用 Caliburn micro(1.3)/MVVM 和 Silverlight。当我更新 itemsource RadGridView 时,我丢失了选定的项目。我找到了一篇关于在实现 MVVM 时实现保存所选项目的行为的博客。我可以获取选定的项目,但一旦刷新 itemsource,我就无法将它们重新设置。有人可以告诉我如何使用 caliburn.micro 和 RadGridVIew 来实现它吗?我认为最好的方法是创建一个 caliburn 微约定,但我只能找到为 selectedItem 而不是 selectedItems 创建约定的参考。

有人可以告诉我如何做到这一点吗?我尝试了以下方法,但它不起作用。

  private static void SetRadGridSelecteditemsConventions()
    {
        ConventionManager
            .AddElementConvention<DataControl>(DataControl.ItemsSourceProperty, "SelectedItem", "SelectionChanged")
            .ApplyBinding = (viewModelType, path, property, element, convention) =>
                                {
                                    ConventionManager.SetBinding(viewModelType, path, property, element, convention, DataControl.ItemsSourceProperty);

                                    if (ConventionManager.HasBinding(element, DataControl.SelectedItemProperty))
                                        return true;

                                    var index = path.LastIndexOf('.');
                                    index = index == -1 ? 0 : index + 1;
                                    var baseName = path.Substring(index);
                                    foreach (var selectionPath in
                                        from potentialName in ConventionManager.DerivePotentialSelectionNames(baseName)
                                        where viewModelType.GetProperty(potentialName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance) != null
                                        select path.Replace(baseName, potentialName))
                                    {
                                        var binding = new Binding(selectionPath) { Mode = BindingMode.TwoWay };
                                        BindingOperations.SetBinding(element, DataControl.SelectedItemProperty, binding);
                                    }
                                    return true;
                                };
    }

谢谢,斯蒂芬

4

1 回答 1

1

您应该为此使用一种行为,因为 SelectedItems 属性是只读的。Telerik 有一个例子,只是这个例子不是针对 caliburn.micro 的。如果将以下类添加到项目中:

public class MultiSelectBehavior : Behavior<RadGridView>
{
    public INotifyCollectionChanged SelectedItems
    {
        get { return (INotifyCollectionChanged)GetValue(SelectedItemsProperty); }
        set { SetValue(SelectedItemsProperty, value); }
    }

    public static readonly DependencyProperty SelectedItemsProperty =
        DependencyProperty.Register("SelectedItems", typeof(INotifyCollectionChanged), typeof(MultiSelectBehavior), new PropertyMetadata(OnSelectedItemsPropertyChanged));


    private static void OnSelectedItemsPropertyChanged(DependencyObject target, DependencyPropertyChangedEventArgs args)
    {
        var collection = args.NewValue as INotifyCollectionChanged;
        if (collection != null)
        {
            collection.CollectionChanged += ((MultiSelectBehavior)target).ContextSelectedItems_CollectionChanged;
        }
    }

    protected override void OnAttached()
    {
        base.OnAttached();

        AssociatedObject.SelectedItems.CollectionChanged += GridSelectedItems_CollectionChanged;
    }

    void ContextSelectedItems_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        UnsubscribeFromEvents();

        Transfer(SelectedItems as IList, AssociatedObject.SelectedItems);

        SubscribeToEvents();
    }

    void GridSelectedItems_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        UnsubscribeFromEvents();

        Transfer(AssociatedObject.SelectedItems, SelectedItems as IList);

        SubscribeToEvents();
    }

    private void SubscribeToEvents()
    {
        AssociatedObject.SelectedItems.CollectionChanged += GridSelectedItems_CollectionChanged;

        if (SelectedItems != null)
        {
            SelectedItems.CollectionChanged += ContextSelectedItems_CollectionChanged;
        }
    }

    private void UnsubscribeFromEvents()
    {
        AssociatedObject.SelectedItems.CollectionChanged -= GridSelectedItems_CollectionChanged;

        if (SelectedItems != null)
        {
            SelectedItems.CollectionChanged -= ContextSelectedItems_CollectionChanged;
        }
    }

    public static void Transfer(IList source, IList target)
    {
        if (source == null || target == null)
            return;

        target.Clear();

        foreach (var o in source)
        {
            target.Add(o);
        }
    }
}

此行为负责集合 RadGridView.SelectedItems 和 MultiSelectBehavior.SelectedItems 之间的同步。

现在我们需要在 ViewModel 中有一个 ObservableCollection

    //Collection holding the selected items
    private ObservableCollection<object> selectedGridItems;
    public ObservableCollection<object> SelectedGridItems
    {
        get
        {
            if (selectedGridItems == null)
                selectedGridItems = new ObservableCollection<object>();

            return selectedGridItems;
        }
        set
        {
            if (selectedGridItems == value) return;
            selectedGridItems = value;
            NotifyOfPropertyChange(() => SelectedGridItems);
        }
    }

    //Deselect all selected items in the gridview
    public void ClearSelectedGridItems()
    {
        SelectedGridItems.Clear();
    }

最后一件事是绑定视图中的行为

    <telerik:RadGridView x:Name="CustomLogs" AutoGenerateColumns="true" SelectionMode="Extended">
        <i:Interaction.Behaviors>
            <local:MultiSelectBehavior SelectedItems="{Binding SelectedGridItems}"/>                
        </i:Interaction.Behaviors>                
    </telerik:RadGridView>

就是这样,希望对你有帮助!

于 2012-03-07T16:18:45.217 回答