Свързване към свойството, преди свойството да бъде инициализирано

Имам клас Project, който зареждам чрез сериализация. Съхранявам екземпляр на този клас в свойство LoadedProject. Опитвам се да свържа етикет към свойство на Project, наречено ProjectName. Докато сериализацията приключи, LoadedProject е нула.

Разбирам, че трябва да настроя DataContext за PropertyChanged да не е null, но настройването на DataContext преди сериализация води до това, че DataContext е null. Задаването му след сериализация пропуска събитието.

Ако се обвързвам към дъщерно свойство, къде трябва да задам DataContext, ако родителят е null?

Клас на проекта:

public class Project : INotifyPropertyChanged
{
    private string _projectFilePath;

    internal string ProjectFilePath 
    { 
        get { return _projectFilePath; }
        set
        {
            _projectFilePath = value;
            this.OnPropertyChanged("ProjectName");
        }
    }

    public string ProjectName
    {
        get { return Path.GetFileNameWithoutExtension(ProjectFilePath); }
    }

    internal static Project Load(string fileName)
    {
        using (var stream = File.OpenRead(fileName))
        {
            var ds = new DataContractSerializer(typeof(Project));
            return ds.ReadObject(stream) as Project;
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    void OnPropertyChanged(string propName)
    {
        if (this.PropertyChanged != null)
            this.PropertyChanged(
                this, new PropertyChangedEventArgs(propName));
    }
}

Main.xaml.cs

private Project LoadedProject { get; set; }
...
bool? result = dlg.ShowDialog();
if (result == true)
{
    // Open document 
    string filename = dlg.FileName;
    DataContext = LoadedProject;  //LoadedProject is currently null. Assigning the DataContext here will not work
    LoadedProject = Project.Load(filename);
}
...

XAML:

 <Label Content="{Binding Path=ProjectName, UpdateSourceTrigger=PropertyChanged, FallbackValue='No Project Loaded'}"></Label>

Редактиране 1: Трябва да се свърже с публични свойства. Името на проекта е променено от вътрешно на публично. Първоначалното обвързване вече работи. PropertyChanged все още е нула.


person Brandon    schedule 06.03.2015    source източник
comment
Какво ще кажете за DataContext = Project.Load(filename);? В противен случай LoadedProject трябва да бъде свойство в друг клас модел на изглед.   -  person Clemens    schedule 06.03.2015
comment
@Clemens Събитието propertychange се задейства по време на сериализация, в който момент DataContext все още е нулев. Присвояването на DataContext след зареждане пак ще пропусне събитието за промяна на свойствата.   -  person Brandon    schedule 06.03.2015


Отговори (2)


Виждам, че вашият LoadedProject е частен, това със сигурност ще причини някои обвързващи проблеми. Първо се уверете, че имотът е настроен като публичен.

public Project LoadedProject { get; set; }

Ако приемем, че се свързвате директно със свойството LoadedProject, просто трябва да приложите INotifyPropertyChanged върху това свойство:

private Project _LoadedProject;

    public Project LoadedProject
    {
        get { return _LoadedProject; }
        set 
        { 
            _LoadedProject = value;
            OnPropertyChanged("LoadedProject");
        }
    }

Това ще принуди потребителския ви интерфейс да обнови обвързванията към този обект, когато се зареди.

person Mike Eason    schedule 06.03.2015
comment
Не съм сигурен, че разбирам. Свързвам моя етикет с LoadedProject.ProjectName. Как добавянето на OnPropertyChanged към събитието LoadedProject set коригира това? - person Brandon; 06.03.2015
comment
@Brandon Тъй като xaml всъщност ще направи две обвързвания зад кулисите обвързване към LoadedProject, след това второ обвързване към обекта, първото обвързване е обвързано с .ProjectName. Така че, ако някой елемент в дървото предизвика промяна на свойството, това ще опресни всички деца. Тъй като обаче LoadedProject е във вашия Main.xaml.cs, вероятно искате да го направите DependancyProperty вместо прилагане на INotiifyPropertyChange - person Scott Chamberlain; 06.03.2015
comment
Всъщност това ще изисква още няколко промени. Вашият DataContext трябва да бъде зададен на this и вашият xaml да бъде променен на {Binding Path=LoadedProject.ProjectName, ..... - person Scott Chamberlain; 06.03.2015
comment
@ScottChamberlain Правейки както промените в отговора, така и вашия коментар, PropertyChanged както в класа на проекта, така и в Main.xaml.cs са null. Задавам DataContext=this точно преди Project.Load() - person Brandon; 06.03.2015
comment
Като алтернатива можете да дадете на родителския си елемент атрибут x:Name и да използвате обвързване на ElementName като: {Binding LoadedProject.ProjectName, ElementName=elementName} Това има същия ефект като настройването на DataContext към себе си. - person Mike Eason; 06.03.2015
comment
@MikeEason Докара ме около 60% от пътя до там. Все още не знам точно защо се провали. В крайна сметка използвах клас BindableBase от тук: danrigby.com/2012/04/01/. Между другото, не вярвам, че питащият се уведомява за коментари, освен ако не коментирате техния въпрос или не използвате препратката @username. - person Brandon; 18.03.2015

Ще трябва да попълните проекта извън изгледа/модела на изглед, към който е обвързан

можете да преместите етикета в подизглед/контрола или да имате някаква стартова логика

person Ewan    schedule 06.03.2015