Подтвердить что ты не робот

Связывание WPF с Listbox selectedItem

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

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

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 к элементу lbRules "SelectedItem". Я попытался привязать свойство textblock text к SelectedRule, но он всегда имеет значение null.

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

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

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

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

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

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

4b9b3361

Ответ 1

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

Затем ваш XAML

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

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

Ответ 2

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

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

UPDATE: относительно привязки свойств 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

Yocoder прав,

Внутри 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

Ответ 4

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

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

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

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

Ответ 5

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

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