Некоторые раздражения с ListView и DataContext - PullRequest
2 голосов
/ 03 сентября 2011

Я написал следующий код C # и XAML:

namespace ListViewExample1
{
public partial class MainWindow : Window
{
    public ObservableCollection<MyColleague> myCollegues = new ObservableCollection<MyColleague>();

    public MainWindow()
    {
        myCollegues.Add(new MyColleague() { Name = "Tim", Surname = "Meier" });
        myCollegues.Add(new MyColleague() { Name = "Martin", Surname = "Hansen" });
        myCollegues.Add(new MyColleague() { Name = "Oliver", Surname = "Drumm" });


        InitializeComponent();
    }

    public ObservableCollection<MyColleague> MyColleagues 
    {
        get { return this.myCollegues; }
    }
}

public class MyColleague
{
    public String Name { get; set; }

    public String Surname { get; set; }
}
}

XAML-код:

<Grid>
    <ListView ItemsSource="{Binding}" DataContext="{Binding RelativeSource={RelativeSource ListViewExample1:MainWindow}, Path=myCollegues}">
        <ListView.View >
            <GridView >
                <GridViewColumn Header="Name" Width="150" DisplayMemberBinding="{Binding Name}"/>
                <GridViewColumn Header="Surname" Width="150" DisplayMemberBinding="{Binding Surname}"/>
            </GridView>
        </ListView.View>
    </ListView> 
</Grid>

Теперь мне нужно установить текстовый текст, но в этот момент у меня возникли некоторые раздражения. Какой синтаксис DataContext-правильный?

Ответы [ 2 ]

4 голосов
/ 03 сентября 2011

Есть десятки способов установить DataContext; никто по своей сути не прав.

Стоит отметить, что нет никакой причины устанавливать DataContext для элемента управления вообще, если все, что вам нужно, это связать одно свойство (ItemsSource, в данном случае). Установка DataContext упрощает привязку нескольких свойств, поскольку все привязки используют один и тот же контекст.

Если вы хотите выполнить привязку данных без какого-либо кода (как вы сказали в комментарии), выбранный вами пример не очень хорош, поскольку вы создаете объект в кода позади. Попробуйте создать класс с помощью конструктора без параметров, например ::

public class MyColleagueCollection : ObservableCollection<MyColleague>
{
   public MyColleagueCollection()
   {
       Add(new MyColleague() { Name = "Tim", Surname = "Meier" });
       Add(new MyColleague() { Name = "Martin", Surname = "Hansen" });
       Add(new MyColleague() { Name = "Oliver", Surname = "Drumm" });
   }
}

Тогда вы можете сделать:

<ListView>
   <ListView.ItemsSource>
      <local:MyColleagueCollection/>
   </ListView.ItemsSource>
   ...
</ListView>

Или вы можете установить DataContext и установить ItemsSource на "{Binding}". Или создайте объект в словаре ресурсов и выполните привязку, используя StaticResource.

Вы также можете создать свою коллекцию как свойство (а не поле, как правильно указывает x0r) класса Window и сделать это:

<Window DataContext="{Binding RelativeSource={RelativeSource Self}}"...

, который теперь сам делает Window объектом контекста данных, позволяя любому элементу окна связываться со своими свойствами напрямую, без использования RelativeSource.

Или (мы еще не закончили), вы можете дать окну имя, а затем привязать к нему по имени:

<ListView ItemsSource=`{Binding ElementName=MyWindow, Path=MyCollection}"...

Давайте даже не будем вдаваться в использование ObjectDataProvider.

То, что в итоге делает большинство людей - это как можно ближе к «правильному» ответу, как вы собираетесь найти - это создание класса модели представления для главного окна, создание его экземпляра в конструкторе окна и установка окна. DataContext к этому объекту. С этого момента любое представление, отображаемое в главном окне, привязывается к свойству этой модели представления. См. Статью Джоша Смита о шаблоне Model / View / ViewModel для действительно хорошо проработанного примера.

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

0 голосов
/ 03 сентября 2011

Ваша привязка к myCollegues не может работать, потому что вы привязываетесь к полю. Вы должны привязать к свойству, которое в вашем случае составляет MyColleagues.

Самое простое решение для установки DataContext будет в коде сзади, при условии, что MainWindow.xaml содержит ListView:

public MainWindow()
{
    [...]    
    InitializeComponent();
    DataContext = this;
}

Вместо того, чтобы хранить ваши данные в выделенном коде, лучшим решением было бы использование подхода MVVM. Там вы храните свои данные в отдельном классе, а затем устанавливаете DataContext для экземпляра этого класса.

Для привязки в XAML используйте следующий синтаксис:

    <ListView ItemsSource="{Binding MyCollegues}" 
              DataContext="{Binding Path=., Mode=FindAncestor, RelativeSource={RelativeSource AncestorType={x:Type ListViewExample1:MainWindow}}}">
...