ProKiLL
@ProKiLL
Системный администратор

Как правильно реализовать «сложную» привязку данных в wpf?

Просьба подсказать новичку как правильно реализовать привязку через XAML следующего класса:
Класс для привязки
using System.ComponentModel;



namespace TestBinding
{
    public class Service : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        private int id;
        private InfoService info;
        public void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        public int Id
        {
            get { return id; }
            set
            {
                id = value;
                RaisePropertyChanged("Id");
            }
        }
        public InfoService Info
        {
            get { return info; }
            set
            {
                info = value;
                RaisePropertyChanged("Info");
            }
        }
    }

    public class InfoService : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        private int id;
        private ServiceMain main;
        public void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
        public int Id
        {
            get { return id; }
            set
            {
                id = value;
                RaisePropertyChanged("Id");
            }
        }
        public ServiceMain Main
        {
            get { return main; }
            set
            {
                main = value;
                RaisePropertyChanged("Main");
            }
        }
    }

    public class ServiceMain : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        private int id;
        private string name;
        public void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        public int Id
        {
            get { return id; }
            set
            {
                id = value;
                RaisePropertyChanged("Id");
            }
        }
        public string Name
        {
            get { return name; }
            set
            {
                name = value;
                RaisePropertyChanged("Name");
            }
        }
    }
}
Заполнил класс
using System.Windows;

namespace TestBinding
{
    public partial class MainWindow : Window
    {
        public Service service;
        public MainWindow()
        {
            InitializeComponent();
            service = 
                new Service{ Id = 0, Info = 
                new InfoService{ Id = 1, Main = 
                new ServiceMain { Id = 2, Name="Тест"} } };
        }
    }
}
Реализация интерфейса
<Window x:Class="TestBinding.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:TestBinding"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <StackPanel DataContext="{Binding Source=service}">
        <TextBlock Text="Service"/>
        <TextBox Text="{Binding Path=Id}"/>
        <TextBlock Text="InfoService"/>
        <TextBox Text="{Binding Path=Id}"/>
        <TextBlock Text="ServiceMain"/>
        <TextBox Text="{Binding Path=Id}"/>
    </StackPanel>
</Window>


Ожидаемый результат увидеть в полях следующие значения:
0
1
2
Но что то пошло не так...
  • Вопрос задан
  • 49 просмотров
Пригласить эксперта
Ответы на вопрос 1
@Meloman19
Ну у вас тут сразу же 2 ошибки.

Первая, DataContext в StackPanel таким образом вы выставить не сможете, потому что у самого окна DataContext пустой. У вас вообще View нигде не пересекается с ViewModel. Хотя как минимум одна точка пересечения быть должна. Обычно это делают в App.xaml.
Открываете App.xaml и удаляете StartupUri. Там же вбиваете Startup и добавляете на это событие обработчик в коде.
private void Application_Startup(object sender, StartupEventArgs e)
{
   MainWindow = new MainWindow
   {
      DataContext = new Service
      {
         Id = 0,
         Info = new InfoService
         {
            Id = 1,
            Main = new ServiceMain { Id = 2, Name = "Тест"}
         }
      }
   };
   MainWindow.Show();
}


Вторая: у вас свойства вложенные. Поэтому нужно вложенные TextBox'ы делать. Код приложен с учётом, что вы сделали, как в предыдущем пункте.
<StackPanel>
      <TextBlock Text="Service"/>
      <TextBox Text="{Binding Path=Id}"/>
      <StackPanel DataContext={Binding Info}>
            <TextBlock Text="InfoService"/>
            <TextBox Text="{Binding Path=Id}"/>
            <StackPanel DataContext={Binding Main}>
                  <TextBlock Text="ServiceMain"/>
                  <TextBox Text="{Binding Path=Id}"/>
            </StackPanel>
      </StackPanel>
</StackPanel>


Ну и сразу замечание на будущее. Имеет смысл PropertyChanged и метод RaisePropertyChanged выделить в отдельный класс, от которого в дальнейшем наследовать все ваши ViewModel (Service, InfoService, ServiceMain).
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы