2009-07-10 12 views
1

OK, sorry für die zu weit gefasste Frage, einige Elemente in XAML deaktivieren, aber lassen Sie uns sehen, was euch vorschlagen ....Wie für eine WPF-Listview

ich eine WPF-Listview durch eine XML-Datei geladen haben, mit XAML (Code unten)

Ich habe eine zweite XML-Datei mit Elementen, die mit denen in meinem ListView übereinstimmen. Wenn jedoch nicht eine Übereinstimmung in der zweiten Datei ist, möchte ich, dass ListItem deaktiviert.

Ein einfaches Beispiel:

My Listview hat darin:

    Joe 
        Fred 
        Jim 

Meine zweite XML-Datei hat (im Wesentlichen) (weil es mit der ersten XML-Datei geladen wurde):

    Joe 
        Jim 

Ich möchte, dass die ListView diese zweite Datei auch irgendwie konsumiert, resultierend in "Fred" wird deaktiviert.

Ich gehe davon aus, dass es eine Art von "Filter" wäre, die ich irgendwo in XAML anwenden würde.

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

Antwort

5

Dies ist eine ziemlich komplexe Aufgabe, daher sollten Sie in Betracht ziehen, dies hauptsächlich im Code und nicht in XAML zu tun. Wenn Sie dies vollständig in Code-Behind tun würden, könnten Sie einen Handler für das ListView.Loaded-Ereignis hinzufügen und dann die gesamte Logik des Hinzufügens von Elementen und des Deaktivierens bestimmter Elemente dort ausführen. Zugegeben, die ListView wäre nicht datengebunden, aber in einem speziellen Fall wie diesem wäre es vielleicht besser, ohne die Bindung.

Um jedoch zu zeigen, dass dies in XAML gemacht werden kann, und mit Mark-up ähnlich wie Ihres, habe ich das folgende Beispiel konstruiert. In meinem Beispiel werden Listen und nicht XmlDataProvider verwendet, aber der Kern davon ist genau derselbe; Sie müssten nur meinen Code, der Listen erstellt, durch Ihren Code ersetzen, der XML lädt.

Hier ist meine Code-Behind-Datei:

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

Dies einfach definiert ein paar Listen und die Person Klassendefinition, die einen Namen Zeichenfolge enthält.

Als nächstes mein XAML mark-up:

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

Hier binde ich die IsEnabled Eigenschaft jeden ListViewItem auf die Eigenschaft Namen der aktuellen Person. Ich stelle dann einen Konverter zur Verfügung, der prüft, ob der Name dieser Person auf der Liste ist. Der ConverterParameter verweist auf die FilterList, die Ihrer zweiten XML-Datei entspricht. Schließlich, hier ist der Konverter:

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

Und das Endergebnis:

alt text

3

Meine Lösung ist nicht so einfach, Sie müssen ein dataTemplate für die Elemente in der Liste erstellen. Die Datenvorlage sollte einen Datentrigger haben, das bedeutet, dass Sie eine Eigenschaft in der Itemquelle haben müssen, die Ihnen sagt, ob das Objekt in der anderen XML-Datei existiert.

so, was ich bin versucht zu sagen, dass u muß die XML-Datei aus dem Code lesen und Ihre eigene Klasse zu generieren, die den Namen prop enthalten und die Exists-Eigenschaft und binden Sie es an die anderen Datei,

Eine andere Lösung, an die ich dachte, wile ich schrieb die Antwort, ist die Isenabled-Eigenschaft des Elements an einen Konverter zu binden, der den Namen erhält und die andere Datei überprüft und einen booleschen Wert zurückgibt.

+0

@Chen könnten Sie ein Beispiel geben, wie so zu einem Konverter zu binden? – KevinDeus

+0

Nicht unbedingt. Sie müssen hierfür kein DataTemplate verwenden. Die Bindung mit Konverter kann im ItemContainerStyle erfolgen. – Charlie

Verwandte Themen