2009-07-10 6 views
1

OK, désolé pour la question trop large, mais nous allons voir ce que les gars .... suggèrentComment désactiver certains éléments XAML pour un ListView WPF

J'ai un ListView WPF chargé par un fichier XML, en utilisant XAML (code ci-dessous)

J'ai un deuxième fichier XML avec des éléments qui correspondent à ce qui est dans ma ListView. Cependant, s'il y a pas une correspondance dans le 2ème fichier, alors je veux que ListItem soit désactivé.

Un exemple simple:

Mon ListView a en elle:

    Joe 
        Fred 
        Jim 

(parce qu'il a été chargé avec le premier fichier XML)

Mon second fichier XML a (essentiellement):

    Joe 
        Jim 

Je veux que le ListView consomme en quelque sorte ce second fichier, résultant en "Fred" étant désactivé.

Je suppose que ce serait une sorte de "filtre" que j'appliquerais quelque part dans XAML.

<ListView Name="lvwSourceFiles" 
      Margin="11,93,0,12" VerticalContentAlignment="Center" 
      HorizontalAlignment="Left" Width="306" 
      Cursor="Hand" TabIndex="6" 
      ItemsSource="{Binding}" 
      SelectionMode="Multiple" 
      SelectionChanged="lvwSourceFiles_SelectionChanged" > 
    <ListBox.DataContext> 
     <XmlDataProvider x:Name="xmlSourceFiles" XPath="AssemblyUpdaterSource/sources/source/File" /> 
    </ListBox.DataContext> 
    <ListView.ItemContainerStyle> 
     <Style TargetType="{x:Type ListViewItem}"> 
      <EventSetter Event="PreviewMouseRightButtonDown" 
         Handler="OnSourceListViewItemPreviewMouseRightButtonDown" /> 
     </Style> 
    </ListView.ItemContainerStyle> 
</ListView> 

Répondre

5

Il s'agit d'une tâche assez complexe, vous devriez donc envisager de le faire principalement en code plutôt qu'en XAML. Si vous deviez le faire entièrement en code-behind, vous pouvez ajouter un gestionnaire pour l'événement ListView.Loaded, puis effectuer toute la logique d'ajout d'éléments et de désactivation de certains éléments. Certes, le ListView ne serait pas lié aux données, mais dans un cas spécial comme celui-ci, vous pourriez être mieux sans la liaison. Cependant, pour montrer que cela peut être fait en XAML, et en utilisant une balise semblable à la vôtre, j'ai construit l'exemple suivant. Mon exemple utilise des listes plutôt que XmlDataProvider, mais l'essentiel est exactement le même; vous auriez juste besoin de remplacer mon code qui construit des listes avec votre code qui charge du XML.

Voici mon code-behind:

public partial class Window2 : Window 
{ 
    private List<Person> _persons = new List<Person>(); 

    public Window2() 
    { 
     InitializeComponent(); 

     _persons.Add(new Person("Joe")); 
     _persons.Add(new Person("Fred")); 
     _persons.Add(new Person("Jim")); 
    } 

    public List<Person> Persons 
    { 
     get { return _persons; } 
    } 

    public static List<Person> FilterList 
    { 
     get 
     { 
      return new List<Person>() 
      { 
       new Person("Joe"), 
       new Person("Jim") 
      }; 
     } 
    } 
} 

public class Person 
{ 
    string _name; 

    public Person(string name) 
    { 
     _name = name; 
    } 

    public string Name 
    { 
     get { return _name; } 
     set { _name = value; } 
    } 

    public override string ToString() 
    { 
     return _name; 
    } 
} 

Cela définit simplement une liste de couple, et la définition de classe Personne, qui est titulaire d'un nom chaîne.

Ensuite, ma marge XAML:

<Window x:Class="TestWpfApplication.Window2" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:local="clr-namespace:TestWpfApplication" 
xmlns:sys="clr-namespace:System;assembly=mscorlib" 
Title="Window2" Height="300" Width="300" 
DataContext="{Binding RelativeSource={RelativeSource Self}}"> 
<Window.Resources> 
    <local:PersonInListConverter x:Key="personInListConverter"/> 
    <ObjectDataProvider x:Key="filterList" ObjectInstance="{x:Static local:Window2.FilterList}"/> 
</Window.Resources> 
<StackPanel> 
    <ListView ItemsSource="{Binding Persons}" 
       SelectionMode="Multiple" 
       Name="lvwSourceFiles" Cursor="Hand" VerticalContentAlignment="Center"> 
     <ListView.ItemContainerStyle> 
      <Style TargetType="{x:Type ListViewItem}"> 
       <Setter Property="IsEnabled" 
         Value="{Binding Name, Converter={StaticResource personInListConverter}, ConverterParameter={StaticResource filterList}}"/> 
      </Style> 
     </ListView.ItemContainerStyle> 
    </ListView> 
</StackPanel> 

Ici, je lie la propriété IsEnabled de chaque ListViewItem à la propriété Nom de la personne actuelle. Je fournis ensuite un convertisseur qui va vérifier pour voir si le nom de cette personne est sur la liste. Le paramètre ConverterParameter pointe vers la FilterList, qui est l'équivalent de votre deuxième fichier XML. Enfin, voici le convertisseur:

public class PersonInListConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     string name = (string)value; 
     List<Person> persons = (parameter as ObjectDataProvider).ObjectInstance as List<Person>; 

     return persons.Exists(person => name.Equals(person.Name)); 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 

Et le résultat final:

alt text

3

Ma solution n'est pas si simple, vous devez créer un DataTemplate pour les éléments de la liste. le modèle de données doit avoir un datatrigger, ce qui signifie que vous devez avoir une sorte de propriété dans la source d'éléments qui vous indique si l'élément existe dans l'autre fichier xml.

donc ce que je veux dire est que u besoin de lire le fichier xml à partir du code et de générer votre propre classe personnalisée qui contiendra l'accessoire de nom et la propriété Exists et le lier à l'autre fichier,

une autre solution que je pensais de wile j'écrivais la réponse est de lier la propriété isenabled de l'élément à un convertisseur qui obtiendra le nom et vérifier l'autre fichier et retourner un booléen.

+0

@Chen pourriez-vous donner un exemple de la façon de se lier à un convertisseur comme ça? – KevinDeus

+0

Pas nécessairement. Vous n'avez pas besoin d'utiliser un DataTemplate pour cela. La liaison avec le convertisseur peut être effectuée dans ItemContainerStyle. – Charlie

Questions connexes