Quelqu'un peut-il aider avec ce qui suit - j'ai joué avec cela, mais je ne peux pas le faire fonctionner pour le reste de ma vie.
J'ai un modèle de vue qui contient les propriétés suivantes;
public ObservableCollection<Rule> Rules { get; set; }
public Rule SelectedRule { get; set; }
Dans mon 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, le ItemsSource fonctionne bien et je reçois une liste d'objets Rule avec leurs noms affichés dans lbRules.
Le problème que je rencontre a pour effet de lier la propriété SelectedRule à SelectedItem de lbRules. J'ai essayé de lier la propriété text d'un textblock à SelectedRule mais elle est toujours nulle.
<TextBlock Text="{Binding Path=SelectedRule.Name}" />
L'erreur que je vois dans la fenêtre de sortie est la suivante: Erreur de chemin BindingExpression: propriété 'SelectedRule' introuvable.
Quelqu'un peut-il m'aider avec cette liaison - Je ne vois pas pourquoi il ne devrait pas trouver la propriété SelectedRule.
J'ai ensuite essayé de changer la propriété text du textblock comme ci-dessous, ce qui fonctionne. Le problème est que je veux utiliser SelectedRule dans mon ViewModel.
<TextBlock Text="{Binding ElementName=lbRules, Path=SelectedItem.Name}" />
Merci beaucoup pour votre aide.
Tout d'abord, vous devez implémenter l'interface INotifyPropertyChanged
dans votre modèle de vue et déclencher l'événement PropertyChanged
dans l'outil de définition de la propriété Rule
. Sinon, aucun contrôle lié à la propriété SelectedRule
ne "saura" qu'il aura été modifié.
Ensuite, votre XAML
<TextBlock Text="{Binding Path=SelectedRule.Name}" />
est parfaitement valable si cette TextBlock
est en dehors de la ListBox
's ItemTemplate
et a la même DataContext
que la ListBox
.
Dans la DataTemplate
, vous travaillez dans le contexte d'une Rule
, c'est pourquoi vous ne pouvez pas vous lier à SelectedRule.Name
- cette propriété n'existe pas sur une Rule
. Pour vous lier au contexte de données d'origine (votre ViewModel), vous pouvez écrire:
<TextBlock Text="{Binding ElementName=lbRules, Path=DataContext.SelectedRule.Name}" />
UPDATE: en ce qui concerne la liaison de la propriété SelectedItem, elle a l'air parfaitement valide, j'ai essayé la même chose sur ma machine et tout fonctionne 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;
}
}
}
}
Yocoder a raison,
Dans DataTemplate
, votre DataContext
est définie sur Rule
et est actuellement traitée par celle-ci.
Pour accéder aux parents DataContext
, vous pouvez également utiliser une RelativeSource
dans votre lien:
<TextBlock Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ____Your Parent control here___ }}, Path=DataContext.SelectedRule.Name}" />
Plus d'infos sur RelativeSource
peuvent être trouvées ici:
http://msdn.Microsoft.com/en-us/library/system.windows.data.relativesource.aspx
Pour moi, j'utilise généralement DataContext
ensemble afin de lier une propriété à deux profondeurs telle que cette question.
<TextBlock DataContext="{Binding SelectedRule}" Text="{Binding Name}" />
Ou bien, je préfère utiliser ElementName
parce que les liaisons ne sont réalisées qu'avec des contrôles d'affichage.
<TextBlock DataContext="{Binding ElementName=lbRules, Path=SelectedItem}" Text="{Binding Name}" />