2

OK J'en ai un bizarre ici. Ce que j'essaie de comprendre, c'est comment avoir une listview, peuplée par une ObservableCollection, mettre à jour une autre ListView, peuplée par une autre ObservableCollection, basée sur la sélection de la première listview puis utiliser un convertisseur de valeurs pour cocher ou décocher une case basée sur la sélection combinée avec l'élément actuel dans la deuxième liste. Cette partie je travaille quelque peu en utilisant la liaison multiple, mais la partie qui m'a bloqué est quand je coche ou décoche un élément dans la deuxième listview je dois pouvoir attraper cet événement et tous les articles actuellement vérifiés dans cette listview une mise à jour une champ de base de données basé sur cela.Listage multiple multisélection ListView

Je sais que cela peut ne pas avoir beaucoup de sens et je me bats sur la façon de le rendre plus clair, mais ci-dessous est le xaml pour les deux listviews et le code pour le convertisseur. Je peux voir que lorsque je coche ou décoche une case dans la liste de lecture secodn que le convertisseur essaye de faire la méthode ConvertBack qui explose, mais si je la mets juste à zéro, alors le code ne souffle plus, mais la case est surlignée en rouge comme une erreur de validation s'est produite. Je ne suis même pas sûr que la multibinding est la voie à suivre ici et j'ai regardé la liste multisélectionnelle de Josh Smith, mais avec la conversion nécessaire, je ne vois pas non plus comment l'implémenter avec succès.

Si quelqu'un a des idées, je l'apprécierais grandement. Aussi mes excuses si je n'ai pas expliqué mon besoin très clairement, mais j'espère avec la description chaotique et le code que vous pouvez voir où je vais avec.

Merci d'avance!

Première ListView qui alimente le second

<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> 

Deuxième ListView avec convertisseur et multiliaison

<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> 

Value Converter

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 }; 
    }} 

Répondre

0

Je pourrais avoir une solution pour la première partie de votre problème, c'est-à-dire comment avoir une listview, peuplée par un ObservableCollection, mettre à jour une autre ListView, peuplée par une autre ObservableCollection, basée sur la première sélection listview.

Mais auparavant, pour cette partie du problème, il suffit de lier la cible ListView sur les éléments sélectionnés de la propriété ListView source qui satisferait vos besoins? Si ce n'est pas le cas, j'ai eu un problème similaire sur un projet récent et j'ai trouvé un comportement appliqué à la liste des sources.

Dire que vous avez un modèle de vue analogue à celle que le DataContext de votre point de vue:

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 }); 
     } 
    } 

Et, selon vous, vous avez quelque chose comme ça:

<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}" /> 

Ensuite, vous pouvez associer ce comportement dans la liste des sources et lui transmettre la source du modèle de vue cible.

==> le comportement:

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); 
       } 

      } 
     } 

    } 
} 

Ce qu'il fait est fondamentalement que lors de l'initialisation, il retreive les éléments de la liste cible et renseigne la liste des sources (à sens unique) et vous abonner à la liste de sélection de source de boîte a changé événement pour remplir la liste des cibles (dans l'autre sens). Ensuite, la commande listbox gest est mise à jour lorsque des éléments sont ajoutés dans le comportement.

Le nouveau XAML ressemble comme ça:

<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}" /> 

Pour la deuxième partie de votre problème, je n'ai pas quelque chose qui me viennent à l'esprit en ce moment ... désolé:/

Questions connexes