WPF liaison à la zone de liste selectedItem

n'importe qui Peut aider avec ce qui suit - été de jouer avec cela, mais ne peux pas pour la vie de me le faire fonctionner.

j'ai un Model view qui contient les propriétés suivantes;

public ObservableCollection<Rule> Rules { get; set; }
public Rule SelectedRule { get; set; }

Dans mon code XAML j'ai;

<ListBox x:Name="lbRules" ItemsSource="{Binding Path=Rules}" 
         SelectedItem="{Binding Path=SelectedRule, Mode=TwoWay}">
<ListBox.ItemTemplate>
    <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="Name:" />
                <TextBox x:Name="ruleName">
                    <TextBox.Text>
                        <Binding Path="Name" UpdateSourceTrigger="PropertyChanged" />
                    </TextBox.Text>
                </TextBox>
            </StackPanel>
    </DataTemplate>
</ListBox.ItemTemplate>

maintenant la source Itemss fonctionne bien et je reçois une liste d'objets de règles avec leurs noms affichés dans lbRules.

le problème que j'ai est de lier la propriété SelectedRule au SelectedItem de lbRules. J'ai essayé de lier la propriété text d'un textlock à SelectedRule mais elle est toujours nulle.

<TextBlock Text="{Binding Path=SelectedRule.Name}" />

L'erreur que je vois dans la fenêtre de sortie est: Bindingexpression Path error: propriété' SelectedRule ' introuvable.

Est - ce que quelqu'un peut m'aider avec cette reliure-Je ne vois pas pourquoi il ne devrait pas trouver la propriété SelectedRule.

j'ai alors essayé de changer la propriété Text de la serrure textuelle comme bellow, ce qui fonctionne. Le problème, c'est que je veux utiliser la règle choisie dans mon ViewModel.

<TextBlock Text="{Binding ElementName=lbRules, Path=SelectedItem.Name}" />

Merci beaucoup pour votre aide.

29
demandé sur Kjartan 2010-01-06 14:13:22

5 réponses

tout d'abord, vous devez implémenter INotifyPropertyChanged interface dans votre modèle de vue et augmenter le PropertyChanged événement dans le setter de la Rule propriété. Sinon aucun contrôle qui se lie à la SelectedRule la propriété "saura" quand elle a été changée.

alors, votre XAML

<TextBlock Text="{Binding Path=SelectedRule.Name}" />

est parfaitement valide si cela TextBlock est à l'extérieur de l' ListBoxItemTemplate et a la même DataContextListBox.

24
répondu arconaut 2010-01-06 14:10:37

à l'intérieur du DataTemplate vous travaillez dans le cadre d'un Rule, c'est pourquoi vous ne pouvez pas lier à SelectedRule.Name -- il n'y a pas de telle propriété sur un Rule. Pour vous lier au contexte original des données (qui est votre ViewModel), vous pouvez écrire:

<TextBlock Text="{Binding ElementName=lbRules, Path=DataContext.SelectedRule.Name}" />

mise à jour: en ce qui concerne la propriété SelectedItem binding, elle semble parfaitement valide, j'ai essayé la même chose sur ma machine et cela fonctionne très bien. Voici mon application de test complète:

XAML:

<Window x:Class="TestWpfApplication.ListBoxSelectedItem"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="ListBoxSelectedItem" Height="300" Width="300"
    xmlns:app="clr-namespace:TestWpfApplication">
    <Window.DataContext>
        <app:ListBoxSelectedItemViewModel/>
    </Window.DataContext>
    <ListBox ItemsSource="{Binding Path=Rules}" SelectedItem="{Binding Path=SelectedRule, Mode=TwoWay}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="Name:" />
                    <TextBox Text="{Binding Name}"/>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Window>

Code derrière:

namespace TestWpfApplication
{
    /// <summary>
    /// Interaction logic for ListBoxSelectedItem.xaml
    /// </summary>
    public partial class ListBoxSelectedItem : Window
    {
        public ListBoxSelectedItem()
        {
            InitializeComponent();
        }
    }


    public class Rule
    {
        public string Name { get; set; }
    }

    public class ListBoxSelectedItemViewModel
    {
        public ListBoxSelectedItemViewModel()
        {
            Rules = new ObservableCollection<Rule>()
            {
                new Rule() { Name = "Rule 1"},
                new Rule() { Name = "Rule 2"},
                new Rule() { Name = "Rule 3"},
            };
        }

        public ObservableCollection<Rule> Rules { get; private set; }

        private Rule selectedRule;
        public Rule SelectedRule
        {
            get { return selectedRule; }
            set
            {
                selectedRule = value;
            }
        }
    }
}
10
répondu Max Galkin 2010-01-06 12:05:45

Yocoder est droit,

à l'intérieur du DataTemplate, le DataContext est défini à Rule actuellement, la manipulation..

Pour accéder aux parents DataContext, vous pouvez également envisager d'utiliser un RelativeSource dans votre liaison:

<TextBlock Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ____Your Parent control here___ }}, Path=DataContext.SelectedRule.Name}" />

Plus d'infos sur RelativeSource peut être trouvé ici:

http://msdn.microsoft.com/en-us/library/system.windows.data.relativesource.aspx

3
répondu Arcturus 2010-01-06 11:32:05

Pour moi, j'ai l'habitude d'utiliser DataContext ensemble pour lier une propriété à deux profondeurs telle que cette question.

<TextBlock DataContext="{Binding SelectedRule}" Text="{Binding Name}" />

Ou, je préfère utiliser ElementName parce qu'il n'atteint les reliures qu'avec les contrôles de vue.

<TextBlock DataContext="{Binding ElementName=lbRules, Path=SelectedItem}" Text="{Binding Name}" />

0
répondu Youngjae 2015-08-05 14:54:08

depuis que vous avez défini votre itemsource à votre collection, votre boîte de texte est liée à chaque article individuel de cette collection. la propriété item selected est utile dans ce scénario si vous essayiez de faire un formulaire maître-détail, ayant 2 boîtes de liste. vous lierez itemsource de la deuxième liste à la collection de règles enfant. en d'autres termes, l'item sélectionné alerte les contrôles extérieurs que votre source a changé, les contrôles internes(ceux qui sont à l'intérieur de votre dataemplate sont déjà au courant des changement.

et pour répondre à votre question oui dans la plupart des cas, définir itemsource est la même chose que définir le datacontext du contrôle.

-6
répondu ecathell 2010-01-06 12:12:30