Привязка не работает с ресурсом приложения - PullRequest
0 голосов
/ 23 июня 2019

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

У меня есть ListBox в представлении, которое имеет свойDataContext устанавливается на модель представления, затем его ItemsSource устанавливается на свойство модели представления, которое ссылается на коллекцию в приложении.Затем ListItems привязываются к свойствам элемента в коллекции.

К сожалению, пока коллекция заполняется, ListBox этого не делает.

Вот файл App.xaml:

    <Application x:Class="TestBindingToAppResource.App"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:TestBindingToAppResource"
        StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
            </ResourceDictionary.MergedDictionaries>
            <!--Declaring this here so that a single instance of the people list is available to the entire application.-->
            <local:People x:Key="MyPeople"/>
        </ResourceDictionary>
    </Application.Resources>
</Application>

И отдельный элемент и его коллекция:

    using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace TestBindingToAppResource
{
    // Contains the data for a single person.
    public class Person : INotifyPropertyChanged
    {
        private string theFirstName;
        public string FirstName { get { return theFirstName; }  set { if (value != theFirstName) { theFirstName = value; NotifyPropertyChanged(); } } }

        private string theLastName;
        public string LastName { get { return theLastName; } set { if (value != theLastName) { theLastName = value; NotifyPropertyChanged(); } } }

        public event PropertyChangedEventHandler PropertyChanged;

        public Person()
        {
            FirstName = "John";
            LastName = "Doe";
        }

        public Person(string firstName, string lastName)
        {
            FirstName = firstName;
            LastName = lastName;
        }

        private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public class People : ObservableCollection<Person>
    {
        public People()
        {

        }
    }
}

Главное окно просто содержит UserControl, содержащий список.

    <Window x:Class="TestBindingToAppResource.MainWindow"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:local="clr-namespace:TestBindingToAppResource"
                Title="MainWindow" Height="350" Width="525">
    <Grid>
        <local:PeopleList x:Name="ListOfPeople"/>
    </Grid>
</Window>

Вот UserControl, который содержит ListBox:

    <UserControl x:Class="TestBindingToAppResource.PeopleList"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:TestBindingToAppResource"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <UserControl.DataContext>
        <local:PeopleViewModel/>
    </UserControl.DataContext>
    <Grid>
        <!--... Other objects ...-->
        <StackPanel Orientation="Vertical" Margin="5,5,5,5">
            <TextBlock Text="Here's a list of people"/>
            <ListBox Name="ListOfPeople" ItemsSource="{Binding People}" Margin="5,0,5,5">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <TextBlock Name="theFirstName" Text="{Binding FirstName}" Margin="5,5,5,5"/>
                            <TextBlock Name="theLastName" Text="{Binding LastName}" Margin="0,5,5,5"/>
                        </StackPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
            <!--... Other objects ...-->
        </StackPanel>
        <!--... Other objects ...-->
    </Grid>
</UserControl>

Наконец, вот модель представления, которая связывает их вместе:

    using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace TestBindingToAppResource
{
    // A view model that allows the list in the view to access the people list in the model.

    public class PeopleViewModel
    {
        public People thePeople { get; private set; }

        public PeopleViewModel()
        {
            // A single instance of the people array is instantiated in the Application object as a resource.
            // This allows any number of view models to access a single instance of the data model.

            thePeople = (People)Application.Current.Resources["MyPeople"];

            // The view model should load the people collection.

            LoadThePeople(thePeople);
        }

        private void LoadThePeople (People thePeople)
        {
            thePeople.Add(new Person("Adam", "Baker"));
            thePeople.Add(new Person("Cindy", "Douglas"));
            thePeople.Add(new Person("Edward", "Fox"));
            thePeople.Add(new Person("Gloria", "Herbst"));
        }
    }
}

Вот результаты:

enter image description here

Итак, мой главный вопрос, конечно, почему это не работает?

Но я считаю, что многие люди имеют одну и ту же цель - иметь один экземпляр модели данных, который можетбыть доступным для ряда моделей представления по всему приложению.Как это обычно делается?

Я использую:

  • WPF
  • C #
  • Win10
  • VS 2019 Community

1 Ответ

0 голосов
/ 23 июня 2019

dataContext пользовательского элемента управления - это PeopleViewModel экземпляр

<UserControl.DataContext>
    <local:PeopleViewModel/>
</UserControl.DataContext>

Затем вы привязываете ListBox к People свойству

<ListBox Name="ListOfPeople" ItemsSource="{Binding People}" Margin="5,0,5,5">

... но PeopleViewModel не делает 't People свойство, только thePeople.Поэтому сделайте это:

<ListBox Name="ListOfPeople" ItemsSource="{Binding thePeople}" Margin="5,0,5,5">

Вы должны были увидеть обязательное предупреждение о пропущенном свойстве People в окне вывода Visual Studio

...