WPF привязка к Listbox selectedItem - PullRequest
30 голосов
/ 06 января 2010

Может кто-нибудь помочь со следующим - поиграл с этим, но не могу на всю жизнь заставить его работать.

У меня есть модель представления, которая содержит следующие свойства;

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

В моем XAML у меня есть;

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

Теперь ItemsSource работает нормально, и я получаю список объектов Rule с их именами, отображаемыми в lbRules.

У меня проблема с привязкой свойства SelectedRule к SelectedItem объекта lbRules. Я попытался привязать свойство text для текстового блока к SelectedRule, но оно всегда равно нулю.

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

Ошибка, которую я вижу в окне вывода: Ошибка пути BindingExpression: свойство SelectedRule не найдено.

Может ли кто-нибудь помочь мне с этой привязкой - я не понимаю, почему она не должна находить свойство SelectedRule.

Затем я попытался изменить свойство text для текстового блока, как показано ниже, что работает. Проблема в том, что я хочу использовать SelectedRule в моей ViewModel.

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

Большое спасибо за вашу помощь.

Ответы [ 5 ]

25 голосов
/ 06 января 2010

Прежде всего, вам необходимо реализовать интерфейс INotifyPropertyChanged в вашей модели представления и вызвать событие PropertyChanged в установщике свойства Rule. В противном случае никакой элемент управления, который связывается со свойством SelectedRule, не будет «знать», когда оно было изменено.

Тогда ваш XAML

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

совершенно допустимо, если TextBlock находится вне ListBox ItemTemplate и имеет тот же DataContext, что и ListBox.

11 голосов
/ 06 января 2010

Внутри DataTemplate вы работаете в контексте Rule, поэтому вы не можете привязать к SelectedRule.Name - такого свойства нет у Rule. Для привязки к исходному контексту данных (который является вашей ViewModel) вы можете написать:

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

ОБНОВЛЕНИЕ: относительно привязки свойства SelectedItem, оно выглядит совершенно корректно, я пробовал то же самое на моей машине, и он работает нормально. Вот мое полное тестовое приложение:

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>

Код:

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;
            }
        }
    }
}
3 голосов
/ 06 января 2010

Йокодер прав,

Внутри DataTemplate ваш DataContext настроен на Rule, который в данный момент обрабатывается ..

Чтобы получить доступ к родителям DataContext, вы также можете использовать RelativeSource в своем переплете:

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

Более подробную информацию о RelativeSource можно найти здесь:

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

0 голосов
/ 05 августа 2015

Для меня я обычно использую DataContext вместе, чтобы связать свойство двух глубин, такое как этот вопрос.

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

Или я предпочитаю использовать ElementName, потому что он достигает привязок только с элементами управления представлением.

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

0 голосов
/ 06 января 2010

, так как вы установили свой источник предметов для своей коллекции, ваше текстовое поле привязано к каждому отдельному элементу в этой коллекции. свойство выбранного элемента полезно в этом сценарии, если вы пытаетесь создать форму с основной информацией, имеющую 2 списка. Вы должны привязать источник элементов второго списка к дочерней коллекции правил. другими словами, выбранный элемент предупреждает внешние элементы управления о том, что ваш источник изменился, внутренние элементы управления (те, которые находятся внутри вашей таблицы данных, уже знают об изменении.

и чтобы ответить на ваш вопрос да, в большинстве случаев установка источника элементов такая же, как установка контекста данных элемента управления.

...