Multibinding Multiselection ListView - PullRequest
       33

Multibinding Multiselection ListView

2 голосов
/ 25 августа 2010

ОК, у меня тут странный вопрос.Я пытаюсь выяснить, как сделать один просмотр списка, заполненный ObservableCollection, обновить другой ListView, заполненный другим ObservableCollection, на основе выбора первого списка, а затем использовать преобразователь значений, чтобы установить или снять флажок на основе комбинированного выборас текущим элементом во втором списке.Эта часть у меня немного работает с использованием мультисвязывания, но часть, которая меня ставит в тупик, - это когда я проверяю или снимаю отметку с элемента во втором просмотре списка, мне нужно иметь возможность получить это событие и все проверенные в данный момент элементы в этом просмотре списка обновитьполе базы данных, основанное на этом.

Я знаю, что это может не иметь большого смысла, и я изо всех сил пытаюсь сделать его более понятным, но ниже приведены xaml для двух списков и код для конвертера.Я вижу, что, когда я устанавливаю или снимаю флажок в списке просмотра secodn, конвертер пытается выполнить метод ConvertBack, который взрывается, но если я установил его так, чтобы он возвращал только ноль, то код больше не взрывается, но флажок выделенв красном цвете, как будто произошла ошибка проверки.

Я даже не уверен, что многосвязное - это то, что нужно, и я посмотрел на материал множественного выбора Джоша Смита, но с необходимым преобразованием я не могу понять, какреализовать это успешно либо.

Если у кого-то есть идеи, я был бы очень признателен.Также мои извинения, если я не объяснил свою потребность очень четко, но я надеюсь с хаотичным описанием и кодом, который вы можете увидеть, куда я иду с ним.

Заранее спасибо!

Первый ListView, который передает второй

<Grid>
                <ListView x:Name="listRule" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="3,3,3,3" ItemsSource="{Binding RuleListing}" exts:Selected.Command="{Binding RuleSelectedCommand}" SelectedIndex="0">
                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <TextBlock Text="{Binding Path=DisplayName}" ToolTip="{Binding Path=Expression}" FontWeight="Bold"/>
                                <TextBlock Text=" ( "/>
                                <TextBlock Text="{Binding Description}" FontStyle="Italic" />
                                <TextBlock Text=" )"/>
                            </StackPanel>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>
            </Grid>

Второй ListView с конвертером и мультисвязью

<Grid HorizontalAlignment="Stretch">
                <Grid.Resources>
                    <converters:RuleToRoleBooleanConverter x:Key='RuleRoleConverter' />                        
                    <DataTemplate x:Key="RoleTemplate">
                        <Grid HorizontalAlignment="Stretch">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="1*" MinWidth="200"/>
                                <ColumnDefinition Width="20"/>
                            </Grid.ColumnDefinitions>
                            <TextBlock Text="{Binding RoleName}" HorizontalAlignment="Left" Margin="3,0,0,0" Grid.Column="0" />
                            <CheckBox HorizontalAlignment="Right" Margin="0,0,3,0" Grid.Column="1">
                                <CheckBox.IsChecked>
                                    <MultiBinding Converter="{StaticResource RuleRoleConverter}">
                                        <Binding ElementName="listRule" Path="SelectedItem" />
                                        <Binding Path="RoleName"/>
                                    </MultiBinding>
                                </CheckBox.IsChecked>
                            </CheckBox>
                        </Grid>
                    </DataTemplate>
                </Grid.Resources>
                <ListView Name="listRoles" ItemsSource="{Binding RoleListing}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
                          SelectionMode="Multiple" ItemTemplate="{StaticResource ResourceKey=RoleTemplate}">
                    <ListView.ItemContainerStyle>
                        <Style TargetType="{x:Type ListBoxItem}">
                            <Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=IsRoleSelected}"/>
                        </Style>
                    </ListView.ItemContainerStyle>
                </ListView>
            </Grid>

ЗначениеКонвертер

public class RuleToRoleBooleanConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (values[0] != null && values[1] != null)
        {
            string expression = ((EliteExtenderRule)values[0]).Expression;
            string role = values[1].ToString();

            if (expression.Contains("R:*") || expression.Contains("R:" + role))
            {
                return true;
            }
        }
        return false;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        return null;// new object[] { (bool)value, null };
    }}

1 Ответ

0 голосов
/ 11 апреля 2011

У меня может быть решение для первой части вашей проблемы, то есть «выяснить, как получить один просмотр списка, заполненный ObservableCollection, обновить другой ListView, заполненный другим ObservableCollection, на основе выбора первого списка».

Но прежде, для этой части проблемы dit просто привязывает целевой ListView к выбранным элементам, свойство исходного ListView удовлетворит ваши потребности?

     <ListView x:Name="listOne" Grid.Column="0" Width="50" Height="200" ItemsSource="{Binding SourceList}" SelectionMode="Extended"  />
    <ListView x:Name="listTwo" Grid.Column="1" Width="50" Height="200" ItemsSource="{Binding ElementName=listOne, Path=SelectedItems}" />

Если нет, у меня была похожая проблема в недавнем проекте, и я придумал поведение, примененное к списку источников.

Скажем, что у вас есть такая модель представления, как DataContext вашего представления:

    public ObservableCollection<BusinessAdapter> SourceList { get; private set; }
    public ObservableCollection<BusinessAdapter> TargetList { get; private set; }
    public Window1()
    {
        InitializeComponent();
        DataContext = this;
        SourceList = new ObservableCollection<BusinessAdapter>();
        TargetList = new ObservableCollection<BusinessAdapter>();

        for (int i = 0; i < 50; i++)
        {
            SourceList.Add(new BusinessAdapter { BusinessProperty = "blabla_" + i });
        }
    }

И, на ваш взгляд, у вас есть что-то вроде этого:

    <ListView x:Name="listOne" Grid.Column="0" Width="50" Height="200" ItemsSource="{Binding SourceList}" SelectionMode="Extended" />
    <ListView x:Name="listTwo" Grid.Column="1" Width="50" Height="200" ItemsSource="{Binding TargetList}" />

Затем вы можете прикрепить это поведение к списку источников и передать ему источник модели целевого представления.

==> Поведение:

public class ListBoxMultiSelectionBehavior
{
    public static IList<BusinessAdapter> GetTargetList(DependencyObject obj)
    {
        return (IList<BusinessAdapter>)obj.GetValue(TargetListProperty);
    }

    public static void SetTargetList(DependencyObject obj, IEnumerable<BusinessAdapter> value)
    {
        obj.SetValue(TargetListProperty, value);
    }

    // Using a DependencyProperty as the backing store for Adapter.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty TargetListProperty =
        DependencyProperty.RegisterAttached("TargetList", typeof(IList<BusinessAdapter>), typeof(ListBoxMultiSelectionBehavior), new UIPropertyMetadata(null, OnListChanged));

    /// <summary>
    /// Model List changed callback
    /// </summary>
    /// <param name="d"></param>
    /// <param name="e"></param>
    private static void OnListChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var mSelector = d as ListView ;

        if (mSelector != null)
        {
            mSelector.SelectionChanged -= MSelectorSelectionChanged;

            //Multiple or Extented selection mode are mandatory
            if (mSelector.SelectionMode == SelectionMode.Single)
            {
                return;
            }
            mSelector.SelectedItems.Clear();

            //"binding" => model to view
            //get the model's list
            var a = GetTargetList(d);
            if (a != null)
            {
                //for each model in the list
                foreach (var ba in a)
                {
                    //in the listbox items collection
                    foreach (var item in mSelector.Items)
                    {
                        //find the correspondance and if found
                        if (((BusinessAdapter)item).BusinessProperty == ba.BusinessProperty)
                        {
                            //add item to selected items
                            mSelector.SelectedItems.Add(item);

                        }
                    }

                }
            }

            //"binding" => view to model
            //subscribe to changes in selection  in the listbox
            mSelector.SelectionChanged += MSelectorSelectionChanged;
        }
    }



    static void MSelectorSelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (e != null)
        {
            var adapter = GetTargetList(sender as DependencyObject);
            var list = adapter;//copy

            if (e.RemovedItems.Count > 0 /*&& e.RemovedItems.Count != list.Count*/)
            {
                foreach (var ba in e.RemovedItems.Cast<BusinessAdapter>())
                {
                    list.Remove(ba);
                }
            }
            if (e.AddedItems.Count > 0)
            {
                foreach (var ba in e.AddedItems.Cast<BusinessAdapter>())
                {
                    list.Add(ba);
                }

            }
        }

    }
}

Что он делает в основном, так это то, что при инициализации он получает целевые элементы списка и заполняет исходный список (в одну сторону), а также подписывается на событие изменения выбора источника в списке, чтобы заполнить целевой список (другой способ). Затем жест целевого списка обновляется при добавлении элементов в поведение.

Новый XAML выглядит так:

    <ListView x:Name="listOne" Grid.Column="0" Width="50" Height="200" ItemsSource="{Binding SourceList}"  SelectionMode="Extended" StackOverflow:ListBoxMultiSelectionBehavior.TargetList="{Binding TargetList}" />
    <ListView x:Name="listTwo" Grid.Column="1" Width="50" Height="200" ItemsSource="{Binding TargetList}" />

Что касается второй части вашей проблемы, у меня сейчас нет того, что приходит мне в голову ... извините: /

...