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.
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' ListBox
ItemTemplate
et a la même DataContext
ListBox
.
à 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;
}
}
}
}
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
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}" />
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.