Are DataContext a kind of new version of DataSource? - c#

What is a DataContext in C#? Are DataContext a kind of new version of DataSource?

(It sounds you mean the FrameworkElement.DataContext property that appears in WPF. If not, oops.)
It's somewhat similar to DataSource, but is much more flexible. In WPF, a DataContext can be literally any object that has properties. To bind to a property, you just specify its name and WPF takes care of the rest for you by fishing the specified property out of the DataContext with some reflection magic. (Fields are not supported.)
For example, if you're binding a view (say, a UserControl or Window) to an Employee object:
class Employee {
public string FirstName { get; set; }
public string LastName { get; set; }
// more stuff. . .
}
then you just set its DataContext to that object. Then the XAML for displaying information from that Employee object could be as simple as:
<Label Content="{Binding FirstName}"/>
<Label Content="{Binding LastName}"/>
Optionally, the DataContext can provide additional functionality that allows for richer binding. For example:
If it implements INotifyPropertyChanged or has dependency properties, changes to the DataContext will be automatically reflected in the UI.
Properties that have setters support two-way binding.
If it implements INotifyDataErrorInfo then you can do form validation.
If it's an ADO.NET object, you get all the usual ADO.NET binding magic.

A DataContext represents the database in either LINQ to SQL or Entity Framework.
It's not quite an analog to anything else in .NET as it handles a lot of different things (change tracking, sql generation, etc).

Related

How can I bind a property?

I'm using the Bing map SDK in my WPF application and the XAML looks like:
<m:Map
x:Name="MyMap"
Grid.Row="1"
CredentialsProvider="KEY"
ZoomLevel="{BINDING MapZoomLevel}"
Mode="Road">
The code behind:
private int mapZoomLevel;
public int MapZoomLevel { get { return mapZoomLevel; } set { mapZoomLevel = value; NotifyOfPropertyChange(() => MapZoomLevel); } }
But this aint working. I guessing it is because I've already bound the Map by setting x:Name. The problem is that I can't remove the x:Name since I'm doing some setup in the view but is there a workaround? I would like to be able to bind the ZoomLevel of the map somehow
In order to data bind, you need to do a few things:
1) You must set the DataContext of the UserControl or Window to the object that contains the property that you want to bind to. That could be like this (in the UserControl or Window code behind) if that object is a separate view model class:
DataContext = new SomeTypeOfViewModel();
Or like this if the property is declared in the code behind:
DataContext = this;
2) You must implement the INotifyPropertyChanged interface or implement DependencyPropertys - you seem to have implemented the INotifyPropertyChanged interface, but you must ensure that you have done it correctly.
3) You must provide a valid Binding Path... BINDING is not valid, so an appropriate Binding Path for you might be this (depending on where you have declared your property):
<m:Map x:Name="MyMap" Grid.Row="1" CredentialsProvider="KEY"
ZoomLevel="{Binding MapZoomLevel}" Mode="Road">
Please read the Data Binding Overview page on MSDN for the full story.
based on your tags you are using Caliburn Micro with this? Datacontext is already set with viewmodel/view from the framework. ZoomLevel="{Binding MapZoomLevel, Mode=TwoWay}" is required.

DataContext changes before I can pass parameters

I have a control with a dependency property which I want to pass which is a property in a class, and I also want to use an ObservableCollection which part of that class as the datacontext for that control.
<mycontrols:News
feedStatus="{Binding newsData.newsStore.feedStatus}"
DataContext="{Binding newsData.newsStore.news}"
/>
The problem here is that the DataContext is used when it evaluates {Binding newsData.newsStore.feedStatus} how can I get it to pass feedStatus first and then set the DataContext.
I would use just the single datacontext if silverlight had the ability to back track up the datacontexts parent, but I don't think this is the case.
Could I set datacontext as a nested parameter?
Set the DataContext to DataContext="{Binding newsData.newsStore} and then bind the feedStatus and news properties inside your UserControl.
Alternatively use multiple dependency properties, instead of the DataContext.
Also, please use .NET naming conventions (PascalCase!). Java style casing makes my eyes cringe.

Loading XAML at runtime using the MVVM pattern in WPF

This is a question that extends from the originally posted here:
Link to loading-xaml through runtime
I'm working on a WPF MVVM application that loads XAML content dynamically from an external source, very similar as the answer in the post above.
Here is what I got so far:
My View declares an instance of the ViewModel as a resource and creates an instance of that ViewModel
In my ViewModel constructor I'm loading a XamlString property coming from an external source (file or db..)
In my view I have a button that user clicks after ViewModel finishes loading and in the click-event code-behind I'm deserializing the dynamically loaded XAML and add it to my grid.
My question is, how can I eliminate code-behind and automate the logic so the View can render the new xaml section dynamically right after the ViewModel is done getting the XAML content and initializing the string property?
Should I use some kind of Messaging Bus so the ViewModel notifies once the property has been set so the View can add the new content?
What troubles me is the fact that ViewModels do have a reference to Views and should not be in charge of generating UI elements.
Thanks in advance!
Edit:
Just to clarify: in my particular case I am not trying to bind a Business Object or Collection (Model) to a UI element (e.g. Grid) which obviously could be accomplished through templates and binding. My ViewModel is retrieving a whole XAML Form from an external source and setting it as a string property available to the View. My question is: Who should be in charge of deserializing this XAML string property into a UI element and add it programmatically to the my grid once my Xaml string property in the VM is set?
This sounds to me more of like a View responsibility, not ViewModel. But the pattern as i understand it enforces to replace any code-behind logic with V-VM bindings.
I have a working solution now and I'd like to share it. Unfortunately I did not get rid of code-behind completely but it works as I expect it to. Here is how it works(simplified):
I have my simplified ViewModel:
public class MyViewModel : ViewModelBase
{
//This property implements INPC and triggers notification on Set
public string XamlViewData {get;set;}
public ViewModel()
{
GetXamlFormData();
}
//Gets the XAML Form from an external source (e.g. Database, File System)
public void GetXamlFormData()
{
//Set the Xaml String property
XamlViewData = //Logic to get XAML string from external source
}
}
Now my View:
<UserControl.Resources>
<ViewModel:MyViewModel x:Key="Model"></ViewModel:MyViewModel>
</UserControl.Resources>
<Grid DataContext="{StaticResource Model}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel>
<!-- This is the Grid used as a Place Holder to populate the dynamic content!-->
<Grid x:Name="content" Grid.Row="1" Margin="2"/>
<!-- Then create a Hidden TextBlock bound to my XamlString property. Right after binding happens I will trigger an event handled in the code-behind -->
<TextBlock Name="tb_XamlString" Text="{Binding Path=XamlViewData, Mode=TwoWay, UpdateSourceTrigger=LostFocus, NotifyOnValidationError=True, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}" Visibility="Hidden" Loaded="tb_XamlString_Loaded" />
</StackPanel>
</Grid>
Basically I created a hidden TextBlock bound to my XAML String property in the ViewModel and I hooked its Loaded event to an event handler in the code behind of the View:
private void tb_XamlString_Loaded(object sender, RoutedEventArgs routedEventArgs)
{
//First get the ViewModel from DataContext
MyViewModel vm = content.DataContext as MyViewModel;
FrameworkElement rootObject = XamlReader.Parse(vm.XamlViewData) as FrameworkElement;
//Add the XAML portion to the Grid content to render the XAML form dynamically!
content.Children.Add(rootObject);
}
This may not be the most elegant but gets the job done. Like some people say, in MVVM there are some cases like this where little code-behind code is needed. It doesn't hurt and also part of this solution still uses the V-VM Binding principles when using the VM to retrieve and populate the XamlString property and exposing it to the View. If we would like to Unit Test the XAML parsing and loading functionality we could delegate it to a separate class.
I hope someone finds this useful!
I'm having trouble understanding what you're saying, so my answer will be based on my interpretation. You should consider posting a sample (simplified) of what you're trying to do.
1) I think you're misunderstanding what MVVM does. MVVM is mostly a binding-based pattern. Your view model should be exposing properties containing business objects and your view should just be binding to those properties. If I am misunderstanding you, and that's what you are doing, then your problem is that your view needs to be aware of when the properties get updated (after you deserialize your xaml, etc). There are two ways to do this: INotifyPropertyChanged interface on your viewmodel, or make your view model inherit from DependencyObject, and make the properties dependency properties. I won't go into details here, because this is a large subject that you should research on Google before making a decision.
2) Generally speaking, you shouldn't use click events inside your view if you're using MVVM. Instead, create properties on the view model of type ICommand (and create ICommand implementations to match, or use an implementation of DelegateCommand (google it) which will allow you to use delegates to implement the interface. The idea is, your view binds to the property and executes the handler directly inside the viewmodel.
3) If you want to push information from the viewmodel to the view, then you should create an event on the viewmodel and subscribe to it in the view, but this is a last resort, only to be used in cases like displaying a new window, etc. Generally, you should be using binding.
4) To be more specific about what you're doing, you should be binding your Grid's ItemsSource property to some property on the view model. Note, the property on the view model should be of type ObservableCollection<T> if you want to be able to add items and get instant updates.
Hope this helps.

XAML inline data binding doesn't work; code behind binding works

Greetings folks!
I'm running into a problem with WPF databinding that I hope you can help out with. I'm new to WPF but an expereienced developer (VB 3.0-6.0, C#).
Here's the scenario:
I have a C# project called MasterPartsData which contains a number of classes which reprsent different types of parts (capacitor, diode, etc). They inherit from a base class called clsPart.
I have another C# WPF project which contains WPF UserControls (as well as a MainWindow) to visually represent the values stored in an individual MasterPartsData (MPD) object. I've created a private field in the usercontrol to hold the object with a getter and setter.
If I create a binding explicitly in the setter for the populated object:
_capacitor = value;
Binding binding = new Binding();
binding.Source = _capacitor;
binding.Path = new PropertyPath("C0uf");
this.txtC0uf.SetBinding(TextBox.TextProperty, binding);
(with _capacitor being the private object variable and C0uf being the property name)
the value correctly displays.
However I don't wish to have to explicitly create each binding in the code behind. My preference is to create the bindings inline in XAML, perhaps with a DataContext pointing to the object.
Unfortunately every different permutation I've tried fails to work; the text box doesn't show data.
I have a couple of suspicions:
1) The binding is correct, but the text box needs to be refreshed.
2) The binding is confused between the private variable and the properties.
3) Maybe the fact that the class is defined in a different project is causing issues.
4) I'm going mad and should check myself into an asylum before someone gets hurt. :)
Any help you can provide would be most appreciated. I'm more than happy to add more information, but didn't want to clutter the question with pages and pages of source.
With respect to your suspicions:
1) I think the default binding behavior of a TextBox is TwoWay, with a LostFocus update trigger, meaning that your UI focus will have to change to another control before the binding will update, if changes are made in the UI.
If changes are made in the code you need to raise the NotifyPropertyChanged event in order for the binding system to see it.
2) This is probably not the case, but it leaves the impression that you're trying to set bindings on your UserControl properties, which is not the way data binding was designed to be used in this particular kind of use case. What you want is to bind data from non-UI classes to dependency properties on your UserControls.
3) This will never matter, as long as your UI project has a reference to your classes.
4) This is a common reaction people have when beginning to use XAML and WPF. It's like instead of being handed a box of Legos, you just got handed an injection molding machine with insufficient instructions, isn't it?
Overall, this is a situation where you might need to examine your design; elements of the "Model-View-ViewModel" pattern will come in handy. If you're unfamiliar with this, it's a development pattern in which you introduce a "ViewModel" class, perhaps you can call it MasterPartsVM which contains an implementation of INotifyPropertyChanged.
The DataContext of your UserControl would be set to this MasterPartsVM class.
A brief code example, using some generic names. Given a ViewModel class with a small backing class that looks like this:
class PartViewModel : INotifyPropertyChanged
{
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
public PartClass Data { get; set; }
public String SomeVMProperty
{
get { return Data.SomeProperty; }
set
{
if (Data.SomeProperty != value)
Data.SomeProperty = value;
this.PropertyChanged(this, new PropertyChangedEventArgs("SomeVMProperty"));
}
}
}
class PartClass
{
public string SomeProperty { get; set; }
}
The XAML of a basic UserControl would look like this:
<UserControl x:Class="WpfApplication1.PartUserControl"
... >
<Grid>
<TextBox Text="{Binding SomeVMProperty}" Margin="68,77,104,176" />
</Grid>
</UserControl>
To connect your data class to this UserControl, you set the UserControl's DataContext property. If you do this in code, it's a matter of having a reference to your user control and the ViewModel, and then setting the property:
MyUserControlInstance.DataContext = new PartViewModel(); // or some existing PartViewModel
That combination of code should work to produce a textbox whose Text property changes every time the SomeVMProperty property is changed.
In a basic binding scenario, if your class looks like this
public class MasterPartsData
{
private string _c0uf;
public string C0uf
{
get { return _c0uf;}
set { _c0uf = value;}
}
public MasterPartsData()
{
C0uf = "Hello World!";
}
}
your XAML would look like this
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" >
<Window.DataContext>
<local:MasterPartsData />
</Window.DataContext>
<Grid>
<TextBlock Text="{Binding Path=C0uf}" />
</Grid>
</Window>
Note, there are many different approaches to setting the DataContext, you don't necessarily just have to do it in the XAML
Also, typically your MasterDataParts class would implement INotifyPropertyChanged

WPF DataGrid Parent Child Data

I'm new to WPF/C#/NET but I have been learning by way of coding some small exercises.
Anyway, I'm stuck. I have seached on here and google and can't find the answer or maybe more correctly can't find an answer I can make sense of.
My problem is this... using the Entity Framework I have two tables. One for Employee details and one for Company details. Employees work for 0 or 1 Company's.
I would like to, via WPF/XAML, define a datagrid to navigate Employees. But within each employee row I would like to show the name of the Company they work for (if there is a relationship) or "Unemployed" in the cases where there is no related Company record.
I have not given details of the tables as it really doesnt matter - the problem is displaying concatentated information from parent/child relationships in a single datagrid.
I dont know what the best approach to this kind of problem is, I'm assuming WPF/DataGrid, so I would really appreciate help on how to go about doing it, the binding (assuming WPF) or even an example of the WPF/XAML
Thanks in advance.
There are many ways to accomplish this - one way you might try is to create a View Model that encapsulates the data you want to display - e.g.
public class EmployeeViewModel
{
private readonly Employee _employee;
public EmployeeViewModel(Employee employee)
{
_employee = employee;
}
public string Name { get { return _employee.Name; } }
public string CompanyName { get { return _employee.Company == null ? "Unemployed" : _employee.Company.CompanyName; } }
}
Then, given an IEnumerable<Employee> you can project your employee data into this view model and set it as the ItemsSource of your DataGrid - e.g.
IEnumerable<Employee> employees = GetEmployeesFromDatabase();
DataGrid1.ItemsSource = employees.Select(x => new EmployeeViewModel(x));
You would normally set the ItemsSource via a xaml binding here rather than setting it directly in code but that would involve the use of a parent ViewModel set as the DataContext of the View and I'm trying to keep things simple.
Another way to accomplish this with a DataGrid would be to forgo the use of a View Model, bind directly to an IEnumerable<Employee> collection and set the column bindings explicitly - e.g.
<DataGrid ItemsSource="{Binding Employees}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Employee Name" Binding="{Binding Name}" />
<DataGridTextColumn Header="Company Name" Binding="{Binding Company.Name}" />
</DataGrid.Columns>
</DataGrid>
Note that with the second example, you won't get "Unemployed" appearing in the Company Name column where there is no associated company for an employee.
EDIT: To clarify the point about setting the items source for your Grid from a property on a 'main' view model bound to the View, you might create a ViewModel class that represents the whole of the current view. e.g.
public class MainViewModel
{
private readonly IEnumerable<Employee> _employees;
public MainViewModel(IEnumerable<Employee> employees)
{
_employees = employees;
}
public IEnumerable<Employee> Employees
{
get { return _employees; }
}
}
You'd set this as the DataContext for the Window / UserControl.
e.g. in simple cases you could do this in the constructor for your Window (although calls to the database should really be asynchronous for WPF apps where possible).
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel(GetAllEmployees());
}
Then you can set up the binding on your Grid like this:
<DataGrid ItemsSource="{Binding Employees}" ...
The data context for the main window is then used for all the child controls contained therein except where you explicitly set the DataContext on a child control. This technique becomes useful where you have more complex ViewModels with many properties and commands. If you are interested in finding out more you should take a look at the MVVM pattern and either or both of the Prism / Caliburn frameworks.

Categories