Sergey Alikin
Sergey Alikin

Reputation: 161

Prism6 shared service and dependency property

I use Prism6 + Unity container for desktop application developing. This is a long-read, sorry. So I ask at top: Prism SetProperty() function is not rising property changed event if input value is Unity singleton. And I understand why: because input value and save value have same reference to singleton instance. RaisePropertyChanged() don't help in this situation. Long-read is statring...

So, I have a dependency property in my UserControl component:

    public static readonly DependencyProperty WorksheetDataProperty =
        DependencyProperty.Register("WorksheetData", typeof(WorksheetDataModel), typeof(SheetUserControl),
        new PropertyMetadata(new WorksheetDataModel(), WorksheetDataPropertyChanged));
    public WorksheetDataModel WorksheetData {
        get { return (WorksheetDataModel)GetValue(WorksheetDataProperty); }
        set { SetValue(WorksheetDataProperty, value); }
    }
    private void WorksheetDataPropertyChanged(WorksheetDataModel worksheetData) {
        if (worksheetData == null)
            return;
        SheetGrid.Model.ActiveGridView.BeginInit();
        this.ClearWorksheetModel();
        this.ResizeWorksheetModel();
        SheetGrid.Model.ActiveGridView.EndInit();
    }
    private static void WorksheetDataPropertyChanged(
        DependencyObject d, DependencyPropertyChangedEventArgs e) {
        ((SheetUserControl)d).WorksheetDataPropertyChanged((WorksheetDataModel)e.NewValue);
    }

It's important for me to invoke actions from WorksheetDataPropertyChanged() function. And scheme without shared service (singleton) is working well: this function is called.

But now I want to share data between several modules. How I see it: I have some "parent" module, which load\save data from storage and shared this data with several other modules, which can modificate shared data, but can't save it. And EventAggregator is not convenient for me: I don't want to create copies of data and then collect it again after modifications. So I register my "shared service" as singleton:

_container.RegisterInstance(new WorksheetDataModel());

Now I can load data from database in "parent" viewmodel to singleton object created in previous step:

    var data = _container.Resolve<WorksheetDataModel>();
    data.Header = args.Header;
    data.User = args.User;
    data.RowHeader = new WorksheetRowHeader(_model.ReadRowHeader(data.Header.WshCode));
    data.ColHeader = new WorksheetColHeader(_model.ReadColHeader(data.Header.WshCode));
    data.Cells = _model.ReadCells(data.Header.WshCode);

Further, I notify child viewmodels about new data in singleton:

    data.OnDataChanged?.Invoke();

And now most important code from child viewmodel. In delegate handler I "apply" new value:

WorksheetData = _container.Resolve<WorksheetDataModel>();

WorksheetData is:

    private WorksheetDataModel _worksheetData;
    public WorksheetDataModel WorksheetData {
        get { return _worksheetData; }
        set { SetProperty(ref _worksheetData, value); }
    }

And problem in this line:

set { SetProperty(ref _worksheetData, value); }

It works only once at first call, because _worksheetData is null. But then refernce of _worksheetData (pointer) setted to singleton and in all next call value and _worksheetData are identical for SetProperty() and, as result, it just quit.

I tried next code:

set { 
    SetProperty(ref _worksheetData, value); 
    RaisePropertyChanged("WorksheetData")
}

But no effect. WorksheetDataPropertyChanged() callback in UserControl component is not calling.

So, I don't know now how to better share some data between several modules. Thanks for any advice.

Upvotes: 0

Views: 60

Answers (1)

Haukinger
Haukinger

Reputation: 10863

WorksheetData does not change, the contents of the WorksheetDataModel instance change.

So to update your bindings,

  • either WorksheetDataModel implements INotifyPropertyChanged and/or uses INotifyCollectionChanged-implementing collections
  • or you let the view model listen to WorksheetDataModel.OnDataChanged and raise its own PropertyChanged to update all bindings to WorksheetData.

Example:

private WorksheetDataModel _worksheetData;
public WorksheetDataModel WorksheetData
{
    get { return _worksheetData; }
    set
    {
        if (_worksheetData != null)
            _worksheetData.OnDataChanged -= DataChangedHandler;
        SetProperty(ref _worksheetData, value);
        if (_worksheetData != null)
            _worksheetData.OnDataChanged += DataChangedHandler;
    }
}

private void DataChangedHandler( object sender, DataChangedEventArgs args )
{
    RaisePropertyChanged( nameof( WorksheetData ) );
}

Upvotes: 0

Related Questions