How to do simple Binding in Silverlight? - silverlight

I understand that Silverlight 3.0 has binding but just want a simple example on how to use this to read a property from a class.
I have a class called Appointment which as a String property called Location:
Public Property Location() As String
Get
Return _Location
End Get
Set(ByVal Value As String)
_Location = Value
End Set
End Property
With a Private Declaration for the _Location as String of course.
I want a XAML element to bind to this property to display this in a TextElement, but it must be in XAML and not code, for example I want something like this:
<TextBlock Text="{Binding Appointment.Location}"/>
What do I need to do to get this to work?
It has to be a Silverlight 3.0 solution as some WPF features are not present such as DynamicResource which is what I'm used to using.
Just to add that my XAML is being loaded in from a seperate XAML File, this may be a factor in why the binding examples don't seem to work, as there are different XAML files the same Appointment.Location data needs to be applied.

You have two options.
If the "Appointment" class can be used as the DataContext for the control or Window, you can do:
<TextBlock Text="{Binding Location}" />
If, however, "Appointment" is a property of your current DataContext, you need a more complex path for the binding:
<TextBlock Text="{Binding Path=Appointment.Location}" />
Full details are documented in MSDN under the Binding Declarations page. If neither of these are working, make sure you have the DataContext set correctly.

You need something in code, unless you want to declare an instance of Appointment in a resource and bind to that but I doubt thats what you want.
You need to bind the Text property to the Property Path "Location" then assign the DataContext of the containing XAML to an instance of the Appointment:-
<Grid x:Name="LayoutRoot" Background="White">
<TextBlock Text="{Binding Location}" />
</Grid>
Then in the control's load event:-
void Page_Loaded(object sender, RoutedEventArgs e)
{
this.DataContext = new Appointment() { Location = "SomePlace" };
}
Note in this case I'm using the default Page control.

If I'm reading correctly, you need to create an instance of Appointment, set the DataContext of the control to that instance and modify your binding to just say: Text="{Binding Location}"
Also, consider implementing INotifyPropertyChanged on your Appointment class to allow the data classes to notify the UI of property value changes.

Related

WPF MVVM User Control

I am working on a WPF app using MVVM. On the main windows is a combo box of customer names. When a customer is selected I want to show the addresses for it.
So I created an Address user control and in the control's code behind I added a DP:
public static DependencyProperty CustomerIdProperty =
DependencyProperty.Register("CustomerId", typeof(int), typeof(AddressView));
public int CustomerId
{
get { return (int)GetValue(CustomerIdProperty); }
set { SetValue(CustomerIdProperty, value); }
}
Next, in the main window I bound the combo to the user control's CustomerId DP:
<vw:AddressView Grid.Row="1"
Grid.Column="0"
x:Name="AddressList"
CustomerId="{Binding ElementName=CustomersList, Path=SelectedCustomer.Id, Mode=TwoWay}"/>
I now have a problem and a question:
Problem: When I run this and select a customer, the setter on the DP never fires. The SelectedCustomer property in the Main Window fires, but not the DP in the user control.
Question: How does the ViewModel for the control know about the CustomerId in the DP?
I have created a small sample app here to demonstrate what I'm doing:
http://sdrv.ms/17OZv1x
I would appreciate any help on this.
Thanks
instead of using dependency properties you can go an easy way when your customer object also has the address property
<AdressView>
<TextBlock Text="{Binding Path=MyAddress.Name}" />
<TextBlock Text="{Binding Path=MyAddress.Street}" />
mainwindow
<ComboBox X:Name=cbo .../>
<local:AddressView DataContext="{Binding ElementName=cbo, Path=SelectedItem}"/>
customer.cs
public Address MyAddress {get;set;}
if you want your dependency property stuff to work, you have to post the code for your addressview, so that we can check the bindings to the dependency properties and you have to give some information how you wanna get the address with your customerid.
CustomerList is of type ComboBox and a ComboBox has no property SelectedCustomer. The property you need for your binding is SelectedItem. You should get binding errors during your debug session in Visual Studio. See Output Window.
To get it work you need to update the binding of the CustomerId-Property to the following.
CustomerId="{Binding ElementName=CustomersList, Path=SelectedItem.Id}"
The TwoWay-Binding is only relevant if you want to change the Id from your AddressView. And I think that you donĀ“t want it. So it can be removed.

wpf source and target binding in two different path

How can I bind a Text property for my TextBox that read from a source but it will store its value to a different target?
Let's say
I have a textbox which is bond to a path in a CollectionViewSource
<Window>
<Window.Resources>
<CollectionViewSource Source="{Binding Source={StaticResource ProgramView}, Path='FK_LevelList_ProgramList'}" x:Key="LevelLookupView" />
</Window.Resources>
<TextBox Name="FeePerTermTextbox" Text="{Binding Source={StaticResource LevelLookupView}, Path='FeePerTerm', Mode=OneWay, StringFormat=c2}"/>
</Window>
When perform save, the value of the TextBox will store to another model that is different from the CollectionViewSource
Thanks
I consider this flawed. What happens if the source gets updated? Should the textbox be overwritten?
The reason for this design is imho, that the UI should reflect the "traits" of the element set as DataContext, therefore i expect it to contain the value i give in the model or in the ui. Now there is of course nothing stopping you from not writing the value in your viewmodel to your model, when receiving the set value from the textbox.
public class Redirecter
{
public string FileName
{
get{return mModel.FileName;}
set{mProxy.FileName = value;}
}
}
But this of course won't work well together with INotifyPropertyChanged. I would use a different approach. Use a model that reflects your ui more. If you open the view fill in this ui model with your settings from model A. If you now save this, save each property into Model B.

Binding inside ContentControl not working

I'm building a graphical designer, based upon an article by Sukram in CodeProject. I'm now trying to extend it so that each item on the canvas binds to a different ViewModel object - i.e. I'm setting the DataContext for each item.
Every item on the designer is actually a ContentControl, into which is placed a different template (based upon which toolbox item was dragged onto the canvas). So I have a template containing a TextBox, and I have a ViewModel object containing a Name property, and I bind the Text property of the TextBox to the Name property of the ViewModel, and ... nothing. I've checked the visual tree with Snoop, and it confirms that the DataContext of the TextBox is the ViewModel object. Yet the TextBox remains empty. And if I modify the (empty) Text in the TextBox, the Name property in the ViewModel does not change. So it looks like the binding is not being applied (or has been removed somehow).
I've found a few posts which talk about the ContentControl messing around with the DataContext and Content properties, but I'm not sure how applicable they all are. The code sets the ContentControl.Content as follows:
newItem = new ContentControl();
ControlTemplate template = toolbox.GetTemplate();
UIElement element = template.LoadContent() as UIElement;
ViewModelItem viewModel = new ViewModelItem() { Name = "Bob" };
newItem.Content = element;
newItem.DataContext = viewModel;
and the XAML for the template is:
<ControlTemplate>
<Border BorderBrush="Black" BorderThickness="1" Width="100">
<TextBox Text={Binding Name}/>
</Border>
</ControlTemplate>
Snoop shows that the TextBox has a DataContext, and if I Delve that DataContext I can see that it has a Name property whose value is "Bob". So why does the TextBox remain empty? Snoop allows me to change that Name property, but the TextBox remains empty.
What am I doing wrong?
A few more details. I've set the VS2010 Debug DataBinding option for the OutputWindow to Verbose, which seems to show that the binding is all being attempted before I set the DataContext. Is it possible that the change to the DataContext is not being recognised?
I've just found this post DataTemplate.LoadContent does not preserve bindings - apparently DataTemplate.LoadContent does not preserve bindings. So it looks like I have to write my own version of LoadContent().
I've realised that the template has come through a XamlWriter, which apparently strips all bindings. This wouldn't be helping.
I've not been able to fix the DataTemplate.LoadContent(), but I realised that I didn't actually need a DataTemplate, since the XamlWriter / XamlReader was already instantiating the UI element that I was after. I found a fix to make the XamlWriter write all the bindings here, and after that it all works.
Thanks for your help.
Maybe you need to tell the binding in the ControlTemplate to look at the TemplatedParent, as is mentioned in this thread?
<TextBox Text="{Binding Path=Name, RelativeSource={RelativeSource TemplatedParent}}"/>
Either that, or try to use a DataTemplate instead.
I can't test this at the moment, so I might just be guessing here.
I would use a DataTemplate, as bde suggests.
You are trying to put some UI on your own data (ViewModel), and this is what Data-Templates are meant for (ControlTemplate is usually what you use if you want to change how e.g. a Button looks).
Change your code to use ContentControl.ContentTemplate with a DataTemplate:
<DataTemplate>
<Border BorderBrush="Black" BorderThickness="1" Width="100">
<TextBox Text={Binding Name}/>
</Border>
</DataTemplate>
Code-behind:
newItem = new ContentControl();
//NOTE: .GetTemplate() needs to return a DataTemplate, and not a ControlTemplate:
newItem.ContentTemplate = toolbox.GetTemplate();
ViewModelItem viewModel = new ViewModelItem() { Name = "Bob" };
newItem.Content = viewModel;
newItem.DataContext = viewModel;

How to bind a textblock's text through XAML using a property?

I am working on a Silverlight application, and I want to bind the simple text property of textblock through a property of string type.
What I did was:
<TextBlock Text="{Binding Name}"/>
Code behind:
public string Name{get;set;}
Name = "Testing..!";
but it will not work.
To expand on anatoliiG's answer (which will work): Data binding refers to properties on the DataContext property of the current element by default. This means that your
<TextBlock Text="{Binding Name}" />
is actually translated to
Set the value of the Text property to this.DataContext.Name
(DataContext is inherited, so if it is not explicitly set on the TextBlock it will check the parent, then the parent of the parent etc etc)
You can resolve your problem in one of two ways:
You can set the value of this.DataContext on the parent to the parent itself (as anatoliiG suggests). This means that when it looks up this.DataContext.Name it will be checking the Page itself, which is where your Name property is found.
You can change your Binding so it looks at the Page instead of Page.DataContext when it is looking up bindings. You can achieve this using the RelativeSource markup extension:
This translates to:
Find the first ancestor of the TextBlock that is of type Page, and bind to the Name property on that object
As a final note, you will also need to implement INotifyPropertyChanged on your DataContext object if you are going to ever change the value of Name.
Oh, and you should be using view models as the DataContext instead of the Page itself!
Answer to your question is: in Page_Loaded event set LayoutRoot.DataContext = this;. But it is more hack, than good practice.
You should take a look into MVVM pattern and INotifyPropertyChanged and create ViewModel which will contain this property.

Silverlight Control Binding

Is there a way to bind a Silverlight control to an object (or database table's row) which contains the values of several control's properties, doing so without by define the binding for each property?
For instance:
Let's say I have the class (or entity based on database table's row) with the following values:
class TextBlockValues
{
public string Text{get; set;}
public string HorizontalAlignment{get; set;}
public string VerticalAlignment{get; set;}
}
I want to bind it to a TextBlock in my silverlight application (again without explicit specify the binding for each property).
Thank you for your time.
There are two parts in a binding: DataContext and the actual Binding objects. Once you set up the data context for an item, all the properties, and children will automatically use that.
For example:
<TextBlock Name="CaptionText" Text="{Binding Text}" HorizontalAlignment="{Binding HorizontalAlignment}" Height="20" TextAlignment="Center" FontStretch="Expanded" FontSize="13" />
And in the .cs file:
CaptionText.DataContext = myObject;
If I understand your question right the answer is no. Even though you can set the control's DataContext you still have to bind which property in the control binds to what in the class.

Resources