You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I have a View called settings that uses a tab navigation bar across the top that is configured for region navigation, and loads "child" views in for the user. I have an interface that defines some std operations for the models, like LoadData. I want to call these methods in the OnLoaded event of the child view, but I have found that the DataContext of the child view is always the Parent Settings view model.
What is the right way to set this up, because right now my app is calling the LoadData on the wrong ViewModel for every View that needs to do that.
All my views are UserControl based items, I have had a look at the Chefs example app in the repo and they seem to use Page for views and UserControl for components in the views, not sure if this my problem.
The Settings View is also a child of the MainView which hosts the main App Navigation.
In the example code below, when the user clicks on "Components" in the settings view tab navigation, the ComponentSettingsView OnLoaded fires, but its DataContext is SettingsModel not ComponentSettingsModel.
Routing Setup:
views.Register(
new ViewMap(ViewModel: typeof(ShellModel)),
new ViewMap<MainPage, MainModel>(),
new ViewMap<DashboardView, DashboardModel>(),
new ViewMap<SettingsView, SettingsModel>(),
new ViewMap<GeneralSettingsView, GeneralSettingsModel>(),
new ViewMap<ComponentSettingsView, ComponentSettingsModel>()
);
routes.Register(
new RouteMap("", View: views.FindByViewModel<ShellModel>(),
Nested:
[
new ("Main", View: views.FindByViewModel<MainModel>(), IsDefault:true, Nested:[
new ("Dashboard", View: views.FindByViewModel<DashboardModel>(), IsDefault: true),
new ("Settings", View: views.FindByViewModel<SettingsModel>(), Nested:[
new RouteMap("GeneralSettings", View: views.FindByViewModel<GeneralSettingsModel>(), IsDefault:true),
new RouteMap("ComponentSettings", View: views.FindByViewModel<ComponentSettingsModel>())
])
]),
]
)
);
public sealed partial class ComponentSettingsView : UserControl
{
public ComponentSettingsView() : base()
{
this.InitializeComponent();
}
private async void ComponentSettingsView_OnLoaded(object sender, RoutedEventArgs e)
{
IBrewhubViewModel model = DataContext as IBrewhubViewModel;
await model.LoadDataAsync();
}
}
Component Settings View model:
public class ComponentSettingsModel : BaseViewModel
{
public ComponentSettingsModel(ILogger<ComponentSettingsModel> logger, IComponentManager componentManager)
{
_logger = logger;
_componentManager = componentManager;
}
private readonly ILogger<ComponentSettingsModel> _logger;
private readonly IComponentManager _componentManager;
private TemperatureSensor _hltTempSensor;
private TemperatureSensor _mashTempSensor;
private TemperatureSensor _boilTempSensor;
private ObservableCollection<string> _oneWireDevices;
public ICommand Save => Command.Create(b => b.Execute(SaveSettings));
public TemperatureSensor HLTTempSensor
{
get => _hltTempSensor;
set => SetProperty(ref _hltTempSensor, value);
}
public TemperatureSensor MashTempSensor
{
get => _mashTempSensor;
set => SetProperty(ref _mashTempSensor, value);
}
public TemperatureSensor BoilTempSensor
{
get => _boilTempSensor;
set => SetProperty(ref _boilTempSensor, value);
}
public ObservableCollection<string> OneWireDevices
{
get
{
return _oneWireDevices;
}
set => SetProperty(ref _oneWireDevices, value);
}
public async ValueTask SaveSettings(CancellationToken ct)
{
}
public override async Task LoadDataAsync()
{
try
{
OneWireDevices = new ObservableCollection<string>()
{
"Device 1","Device 2"
};
_componentManager.ValidateConfiguration();
_componentManager.LoadComponents();
HLTTempSensor = _componentManager.HLTTempSensor;
MashTempSensor = _componentManager.MashtunTempSensor;
BoilTempSensor = _componentManager.BoilTempSensor;
}
catch (Exception e)
{
_logger?.LogError(e, "Unable to load data");
}
}
}
Base View Model:
public interface IBrewhubViewModel
{
Task LoadDataAsync();
}
public class BaseViewModel : INotifyPropertyChanged, IBrewhubViewModel
{
private string _busyMessage;
protected DispatcherQueue Dispatcher => DispatcherQueue.GetForCurrentThread();
public event PropertyChangedEventHandler PropertyChanged;
public string BusyMessage
{
get => _busyMessage;
set => SetProperty(ref _busyMessage, value);
}
protected virtual bool SetProperty<T>(ref T backingVariable, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(backingVariable, value)) return false;
backingVariable = value;
OnPropertyChange(propertyName);
return true;
}
protected void OnPropertyChange([CallerMemberName] string propertyName = null)
{
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
DispatchAsync(() => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)));
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
}
protected async Task DispatchAsync(DispatcherQueueHandler callback)
{
var hasThreadAccess = Dispatcher.HasThreadAccess;
if (hasThreadAccess)
{
callback.Invoke();
}
else
{
var completion = new TaskCompletionSource();
Dispatcher.TryEnqueue(() =>
{
callback();
completion.SetResult();
});
await completion.Task;
}
}
public virtual Task LoadDataAsync()
{
return Task.CompletedTask;
}
}
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
-
I have a View called settings that uses a tab navigation bar across the top that is configured for region navigation, and loads "child" views in for the user. I have an interface that defines some std operations for the models, like LoadData. I want to call these methods in the OnLoaded event of the child view, but I have found that the DataContext of the child view is always the Parent Settings view model.
What is the right way to set this up, because right now my app is calling the LoadData on the wrong ViewModel for every View that needs to do that.
All my views are UserControl based items, I have had a look at the Chefs example app in the repo and they seem to use Page for views and UserControl for components in the views, not sure if this my problem.
The Settings View is also a child of the MainView which hosts the main App Navigation.
In the example code below, when the user clicks on "Components" in the settings view tab navigation, the ComponentSettingsView OnLoaded fires, but its DataContext is SettingsModel not ComponentSettingsModel.
Routing Setup:
Main View:
Settings View
Settings View Model:
Component Settings View
Component Settings View model:
Base View Model:
Beta Was this translation helpful? Give feedback.
All reactions