2013-07-10 2 views
0

Это должно быть очень простое решение, но поиск через Интернет кажется несколько разных способов сделать привязку, и NONE, похоже, действительно работает.Чрезвычайно простое связывание серебристого света не работает

Я создал простое приложение с кнопкой, текстовым полем и списком. Пользователь добавляет текст в текстовое поле, нажимает «Добавить», и я хочу, чтобы текст отображался в списке. Обратите внимание, что кнопка «Добавить» создаст Личность с первым именем текста в текстовом поле и фамилию «Джонс». Это просто для того, чтобы выяснить, как получить привязку к реальной работе. У меня есть ObservableCollection, но я не могу даже понять, как помещать ресурс в объект внутри самого класса. Возможно ли это? мне нужно создать отдельный класс для привязки?

Вот полный XMAL

<UserControl x:Class="simpleBinding.MainPage" 
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:z="clr-namespace:simpleBinding" 
mc:Ignorable="d" 
d:DesignHeight="300" d:DesignWidth="400"> 

<Canvas x:Name="LayoutRoot" Background="White"> 
    <Button Name="_b" Content="Add" Height="23" HorizontalAlignment="Left" VerticalAlignment="Top" Width="58" Canvas.Left="90" Canvas.Top="5" Click="OnAdd" /> 
    <TextBox Name="_tb" Canvas.Left="12" Canvas.Top="4" Height="24" Width="72"></TextBox> 
    <ListBox Name="_list" Canvas.Left="18" Canvas.Top="41" Height="98" Width="190" /> 
</Canvas> 

и вот полный код позади

namespace simpleBinding 
{ 
    public partial class MainPage : UserControl 
    { 
     public ObservableCollection<Person> PersonList = new ObservableCollection<Person> (); 
     public MainPage() 
     { 
      InitializeComponent(); 
     } 

     private void OnAdd(object sender, RoutedEventArgs e) 
     { 
      PersonList.Add(new Person(_tb.Text, "Jones")); 
     } 
    } 

    public class Person 
    { 
     public string FirstName {private set; get;} 
     public string LastName {private set; get; } 

     public Person(string fName, string lName) 
    { 
      FirstName = fName; 
     LastName = lName; 
    } 
    } 
} 

спасибо за любую помощь, Крисом

+0

Вы не имеют Binding логики в вашем XAML. Посмотрите на это в первую очередь. – aqwert

+1

Да, сначала посмотрите свой XAML, у них нет привязки к ListBox и DataContext.same, как сказал @aqwert. – Ravuthasamy

ответ

1

Следуя временной шкале, вы можете видеть, что это заняло у меня неделю, чтобы наконец добраться до решения. Я отправляю его здесь сейчас в надежде, что кто-то еще не потратит много времени. Кажется, что есть много сообщений о том, как справиться с этой проблемой, и примеры ограничены. Они либо показывают только C# или Xaml. Тогда CollectionChanged и PropertyChanged не рассматриваются в одном примере.

Это простой пример, который реализует как измененную коллекцию, так и свойство. Как и связывание в Xaml

Вот Xaml.

<UserControl x:Class="simpleBinding.MainPage" 
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:src="clr-namespace:simpleBinding" 
mc:Ignorable="d" 
d:DesignHeight="300" d:DesignWidth="400"> 

<Canvas x:Name="LayoutRoot" Background="White" DataContext="{Binding}"> 
    <Canvas.Resources> 
     <src:PersonList x:Key="myDataSource"></src:PersonList> 
    </Canvas.Resources> 

    <Button Name="_b" Content="Add" Height="23" HorizontalAlignment="Left" VerticalAlignment="Top" Width="58" Canvas.Left="90" Canvas.Top="5" Click="OnAdd" /> 
    <Button Canvas.Left="150" Canvas.Top="5" Content="Edit" Height="23" Name="button1" Width="58" Click="OnEdit" /> 
    <TextBox Name="_tb" Canvas.Left="12" Canvas.Top="4" Height="24" Width="72"></TextBox> 
    <ListBox Name="_list" Canvas.Left="18" Canvas.Top="41" Height="98" Width="190" ItemsSource="{Binding Source={StaticResource myDataSource}}" > 
     <ListBox.ItemTemplate> 
      <DataTemplate> 
       <StackPanel Orientation="Horizontal"> 
        <TextBlock Text="{Binding Path=FirstName}" Margin="0,0,2,0" /> 
        <TextBlock Text="{Binding Path=LastName}" /> 
       </StackPanel> 
      </DataTemplate> 
     </ListBox.ItemTemplate> 
    </ListBox> 

</Canvas> 

  1. Добавить Xmlns, которые ссылаются на ваш код позади. В этом случае мое пространство имен - xmlns: src, тогда вы можете использовать VS intellisense для перехода к правильному классу.
  2. Добавить ресурс в элемент layoutRoot. В моем случае я использую холст, но это может быть Grid или Stackpanel и т. Д.
  3. С объявленным ресурсом теперь вы можете установить привязку ItemSource в ListBox.
  4. Я решил использовать шаблон для отображения данных, которые, как я считаю, действительно круты (лучшая часть Xaml!) В этом случае есть два текстовых блока, но если у моего базового источника данных есть изображение, я мог бы использовать это, чтобы графически отображать данные. Связывание для каждого текстового поля может быть установлено, поскольку открытые свойства объекта объявлены в коде C#. Что будет обсуждаться в следующем

C# код позади

namespace simpleBinding 
{ 
public partial class MainPage : UserControl 
{ 
    public PersonList m_pList = new PersonList(); 

    public MainPage() 
    { 
     InitializeComponent(); 
     _list.ItemsSource = m_pList; 
     m_pList.Add(new Person("John", "Doe")); 

    } 

    private void OnAdd(object sender, RoutedEventArgs e) 
    { 
     m_pList.Add(new Person("Jones", _tb.Text)); 

    } 

    private void OnEdit(object sender, RoutedEventArgs e) 
    { 
     m_pList[1].FirstName = _tb.Text; 
    } 
} 

public class PersonList : ObservableCollection<Person> , INotifyPropertyChanged 
{ 
    public PersonList() : base() // need to call base on intialization otherwise the binded resource is not updated. 
    { 
     Add(new Person("Willa", "Cather")); 
     Add(new Person("Isak", "Dinesen")); 
     Add(new Person("Victor", "Hugo")); 
     Add(new Person("Jules", "Verne")); 


    } 

} 

public class Person : INotifyPropertyChanged 
{ 
    private string _fName; 
    private string _lName; 

    public event PropertyChangedEventHandler PropertyChanged; 



    public string FirstName 
    { 
     set 
     { 
      _fName = value; 
      NotifyPropertyChanged("FirstName"); 
     } 
     get 
     { 
      return _fName; 
     } 
    } 
    public string LastName 
    { 
     set 
     { 
      _lName = value; 
      NotifyPropertyChanged("LastName"); 
     } 
     get 
     { 
      return _lName; 
     } 
    } 



    public Person(string fName, string lName) : base() 
    { 
     FirstName = fName; 
     LastName = lName; 
    } 

    public override string ToString() 
    { 
     return String.Format("{0} {1}", FirstName, LastName); 
    } 


    private void NotifyPropertyChanged(String propertyName = "") 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 


} 

}

я выбрал использовать ObservableCollection, потому что он реализует INotifyCollectionChanged. Открывается переменная public, которая позволяет вам привязываться к ресурсу, объявленному в Xaml. (Лучше код, сделать вар приватным и имеют свойство, которое выставляет переменную через получить!)

  1. ListBox _List должен иметь его свойство ItemsSource в Кодексе За !!! без этого, когда вы меняете список (добавлять, удалять и т. д.), пользовательский интерфейс не обновляется. И на самом деле вам не требуется привязка в ListBox вообще, потому что мы устанавливаем исходный код в коде за ним, но это хорошо, однако в том, что в конструкторе с этим связанным элементом управления вы можете видеть, что привязка работает, потому что есть четыре имени добавляется при создании экземпляра PersonList.
  2. В ObservableCollection необходимо добавить INotifyCollectionChanged. Без этого при изменении свойства пользовательский интерфейс НЕ изменяется.
  3. Свойства, которые должны отображаться в пользовательском интерфейсе, должны быть реализованы в объекте, который содержится в ObservableCollection (в моем случае класс Person подвергается как FirstName, так и LastName), а затем эти свойства могут быть связаны в Xaml (см. textBlocks's)
  4. В INotifyPropertyChanged требуется реализовать событие PropertyChanged, то есть публичное событие PropertyChangedEventHandler PropertyChanged;
  5. Чтобы действительно запустить это событие, для объекта «Человек» необходимо реализовать код для этого, что в моем случае является методом NotifyPropertyChanged. Каждый раз, когда свойство задано, я вызываю этот метод, который, в свою очередь, видит, что событие PropertyChanged не является нулевым, а если нет, то оно вызывает это событие.
  6. Вот ключ к изменениям свойств, без добавления коллекции INotifyPropertyChanged в Observable. Свойство PropertyChanged имеет значение null.

Надеется, что это помогает кто-то

2

Для иллюстрации Ravuthasamy в & aqwert годов Комментарии. Сначала вы должны установить DataContext. Вы можете установить this в DataContext или читать, как MVVM работы (Это хорошая Silvelight связывания модели):

C#

public MainPage() 
{ 
    InitializeComponent(); 
    DataContext = this; 
} 

После вы можете связать свойство класса к элементам:

Xaml

<ListBox 
    ItemsSource="{Binding PersonList}" 
    Canvas.Left="18" 
    Canvas.Top="41" 
    Height="98" 
    Width="190" /> 
+1

Просто чтобы добавить к этому шаблону. В структуре XAML есть две разные части: разметка XAML и связанный с ней код. Эти две части объединены в один объект после компиляции. К сожалению, DataContext не знает, чтобы привязываться к себе. По умолчанию DataContext является DataContext его контейнера. Поэтому, если вы не перенаправляете его, ваш DataContext - это DataContext вашего контейнера. Это очень распространенная ошибка, и каждый забывает раз и навсегда. Просто направьте свой DataContext сразу после InitializeComponent() или даже лучше в самой разметке. – Tigertoy

+0

Это не работает. Установка DataContext в MainPage для этого или PersonList И я добавил ItemSource = "{Binding PersonList}" в список Xaml, а также добавление ресурса в файл: MtnManChris

Смежные вопросы