Reputation: 157
I have my first WPF working fine with an ObjectDataProvider in the XAML:
<ObjectDataProvider x:Key="WaitingPatientDS" ObjectType="{x:Type local:clsPatients}">
<ObjectDataProvider.ConstructorParameters>
<sys:Boolean>True</sys:Boolean>
</ObjectDataProvider.ConstructorParameters>
</ObjectDataProvider>
However, I don't like using this because if there is a connection error, I can't trap it and the program just barfs out.
So, what I've been trying to do is to instantiate the collection object directly in the codebehind...
public partial class MainWindow : Window
{
ListBox _activeListBox;
clsPatients oPatients;
public MainWindow()
{
oPatients = new clsPatients(true);
...and then reference it in my databinding as so:
<StackPanel x:Name="stkWaitingPatients" Width="300" Margin="0,0,0,-3"
DataContext="{Binding Mode=OneWay, Source={StaticResource local:oPatients}}">
But, I'm getting "local:oPatients was not found".
So...what am I doing wrong in referencing this and/or how would someone else accomplish this data binding so that I can actually trap for connection errors and divert the main form to a user-friendly error form?
THANKS!
Upvotes: 2
Views: 3363
Reputation: 178630
I'd move the data access logic into a separate service, and perhaps into its own assembly entirely to enforce your intended separation of concerns. Then I'd have a view model use said service to retrieve data and expose it for the view. Then the view would simply bind to the view model and wouldn't care whether the data came from a database or whatever.
I would suggest reading up on separation of concerns, service locator/dependency injection, and MVVM.
Upvotes: 3
Reputation: 1067
You're getting that error because oPatients
is not a StaticResource
. It would have to be defined in the ResourceDictionary
the way your ObjectDataProvider
was, but as a class member it is not. You could expose it as a public property:
public clsPatients Patients { get; set; }
Then bind to it directly:
<!-- MainWindowRoot is the x:Name of your Window element. -->
<StackPanel x:Name="stkWaitingPatients" Width="300" Margin="0,0,0,-3"
DataContext="{Binding Patients, ElementName=MainWindowRoot, Mode=OneWay}">
Assuming I haven't made some stupid mistake, that should work. However, it still doesn't solve your problem because you're loading the data in the constructor, which means that any exceptions will cause clsPatients
construction to fail, which in turn will cause MainWindow
construction to fail, which you cannot properly handle because it's a rats next of a stack trace that's indistinguishable from a legitimate construction failure.
Kent is 100% right: The data should come from an external provider.
You may have resource limitations, but you can still establish good design even if you can't implement a tiered architecture. At bare minimum, establish separation of concerns by loading the data in a separate data provider class then passing the fully-formed data into the window. That allows you to isolate failures where they occur, and keep your code somewhat more loosely coupled.
public class PatientDataProvider
{
public PatientDataProvider(WhatItNeedsToConnect whatItNeedsToConnect)
{
// this doesn't connect because the constructor shouldn't fail because of a connection failure
}
public clsPatients GetPatientData(bool yesOrNo)
{
// this can fail because of a connection error or some other data loading error
}
}
and invoke it as:
PatientDataProvider provider = new PatientDataProvider(whatItNeedsToConnect);
clsPatients patients = null;
try {
patients = provider.GetPatientData(true);
MainWindow w = new MainWindow { Patients = patients; };
w.Show();
}
catch (WhateverExceptionGetsThrownByProvider e)
{
MessageBox.Show("Could not load patients: " + e.Message);
}
Also, if clsPatients
is self-refreshing, make sure it implements INotifyPropertyChanged
or INotifyCollectionChanged
as appropriate in order for the binding targets to update when the data changes.
Upvotes: 3