Two way datatable binding in WPF - wpf

I have a datagrid (A C1 datagrid, in this case) bound to a property in my View Model. The XAML for the datagrid looks like this:
<c1:C1DataGrid
AutoGenerateColumns="False"
IsReadOnly="False"
Margin="5" Width="auto"
MinWidth="250"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Name="dgNotifAssign"
CanUserAddRows="True"
ItemsSource="{Binding Path=notifCodeSubs.notification_configuration}"
>
<c1:C1DataGrid.Columns>
<c1:DataGridTextColumn
Binding="{Binding Path=user_id}"
Header="Recipient"
VerticalAlignment="Stretch"
SortMemberPath="user_id"
>
The property that it is bound to, in my viewmodel, looks like this:
Public Property notifCodeSubs As dsPeruseFM
Get
If _notifCode Is Nothing Then
_notifCode = New dsPeruseFM
End If
Return _notifCode
End Get
Set(ByVal value As dsPeruseFM)
MsgBox("If you can see this, success!")
End Set
End Property
In the codebehind I create an instance of the viewmodel and set the datacontext of the xaml to that instance, rather simple...
Dim vm As New ctrlAlertNotifyVM
As well as:
ctrlAlertNotifyXML.DataContext = vm
The above configuration compiles and reads data just fine. The grid is populated with all the correct data, etc. The problem comes when I try to add Mode=twoway to the ItemsSource on the datagrid. At that point VS2010 spits out the following error:
A TwoWay or OneWayToSource binding cannot work on the read-only property 'notification_configuration' of type 'PeruseFM.dsPeruseFM'.
I'm quite sure that all of my properties are read/write. And while the set command for this is nothing more than a message box at this point, it doesn't seem like I can even access that.
So the question is... has anybody ever encountered this issue before?
Update, response to question "What does notification_configuration look like?" from sixlettervariables:
Public Function codeChanged(Optional ByVal x As String = "")
If _notifCode Is Nothing Then
_notifCode = New dsPeruseFM
End If
taNotifSubs.fillNotifSubs(notifCode:=x, dataTable:=_notifCode.notification_configuration)
Return _notifCode
End Function

You've shown us that notifCodeSubs is read/write, however, that is not the actual property you've bound to.
From this viewpoint, the error message is fairly self-explanatory:
...read-only property 'notification_configuration'...
Therefore you cannot apply TwoWay binding to that property as an ItemsSource.

Related

Using BooleanToVisibilityConverter without MVVM

I'm using VB.Net & WPF (not using MVVM as I'm not familiar with it)
I have a Toolbar control in my User Control Style whose Visibility needs to be set from code behind so I decided to use BooleanToVisibilityConverter. I have a Boolean variable in my code depending on whose value toolbar visibility needs to be set.
How can I achieve this.
Thanks in advance
Edit
Tried following
XAML
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibility"/>
</Window.Resources>
<ToolBarTray Visibility="{Binding Converter={StaticResource BooleanToVisibility}}"/>
VB.Net Code
Dim IsToolbarVisible As Boolean = True
Public Property ToolbarVisibality As Boolean
Get
Return IsToolbarVisible
End Get
Set(value As Boolean)
IsToolbarVisible = value
End Set
End Property
How to Pass value of IsToolBarVisisble to Boolean TO Visibility Converter ???
Right now your binding uses the DataContext as value. You'll want to set the DataContext to the object holding a public IsToolbarVisible property (is that a property? looks like a field, i don't speak vb) and set the Binding.Path to IsToolbarVisible. Read the data binding overview.

WPF - expose binding methods for inherited column

A reoccurring issue I have is needing to create enhanced text columns for datagrids. By that I mean columns that act just like normal text columns, but with an additional graphic or feature, like an image displayed next to the text. So I'm using template columns, but apparently this means having to "start from scratch" in generating a lot of the features expected of a normal text column, such as the textbox editing template:
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox
FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}"
Text="{Binding Path=[binded text], Mode=TwoWay, UpdateSourceTrigger=LostFocus}"/>
I want to define a column that's inherited from DataGridTemplateColumn, then dump all this code into it, so I can reuse these columns with any datagrid I wish. But as shown above, I can't declare the binding in the class definition because that obviously depends upon usage.
How can I define an inherited datagrid column that makes use of child controls (specifically the cell editing textbox in this case), but still allows binding to be set for these controls when the column has been declared with xaml inside some actual datagrid?
So far I've tried to expose a method to do this, but it's not working:
Public Class MyTextColumn
Inherits DataGridTemplateColumn
....
Public Property EditorBinding As String
Get....
Set(value As String)
Dim b As New Binding(value)
b.Mode = BindingMode.TwoWay
b.UpdateSourceTrigger = UpdateSourceTrigger.LostFocus
Dim tb = DirectCast(Me.CellEditingTemplate.LoadContent, TextBox)
tb.SetBinding(TextBox.TextProperty, b)
End Set
End Property
Not working, my best guess is I'm not setting the Binding.Source, but I have no idea what I should be setting it to. It's getting pretty frustrating.
So if I understand you correctly, you want to be able to bind the text property of the TextBox to something on the parent control which will hold this child control of yours. You can't do that using the normal property (I'm guessing you got the "Can't bind because it's not the dependency property" exception or something similar).
This is how I usually do it without any problems. First you need to define a dependency property in the code behind. This should show you how to do it in the VB.net (I really really suck at VB.net so I won't pretend to give you any advice on that). Check the first example in VB.net. What you need to change first is from Boolean to String, you will also probably want to change the property name. Be careful to leave the "Property" part of the name where it stands in the example. GetType(MyCode) should be changed to the name of the class where you are implementing the dependency property (the name of your MyTextColumn class)
In the MyTextColumn xaml, it should look something like this:
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox
FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}"
Text="{Binding Path=IsSpinning, RelativeSource={RelativeSource AncestorType=DataGridTemplateColumn}, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"/>
I've put the original property name IsSpinning, you should put there your chosen name. Also, you might have to fix the relative source if the base class is not DataGridTemplateColumn. This should pick up anything comming to your custom control.
The final step is to use your control:
<controls:MyTextColumn IsSpinning="{binding PropName}"/>
You basically bind it to whatever string you want. Feel free to write up any problems that you might have with my explanation or code and I'll fix my answer accordingly.

PRISM-MVVM, ItemsControl problem with View injection

I need to display multiple instances of a basketDetailsView.xaml within a region placed in basketView.xaml, but I'm getting the following errormessage when i debug my code:
"An exception occurred while creating a region with name 'basketRegion'. The exception was: System.InvalidOperationException: ItemsControl's ItemsSource property is not empty. This control is being associated with a region, but the control is already bound to something else. If you did not explicitly set the control's ItemSource property, this exception may be caused by a change in the value of the inherited RegionManager attached property"
The basketView XAML contains an ItemsControl tag defined like this
<ItemsControl x:Name="basketItemsControl"cal:RegionManager.RegionName="basketRegion"/>
The view also has a listbox where I can uncheck/check the BasketDetailsViews I want to look at:
<ListBox x:Name="basketListBox" ItemsSource="{Binding basket}" MinWidth="200">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox commands:Checked1.Command="{Binding DataContext.CheckCommand,ElementName=basketListBox}" Content="{Binding basketName}" ></CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox
When I run without debugging it executes fine and I can pop in/out the different basketDetailsViews, but when debugging the above mentioned error shows. What Am i doing wrong?
EDIT:
Public Sub AddCageDetailsView(ByVal BasketName As String)
Dim basketRegion = _RegionManager.Regions("basketRegion")
Dim view = _Container.Resolve(Of basketDetailsView)()
Dim viewmodel = _Container.Resolve(Of basketDetailsViewModel)()
view.ApplyModel(viewmodel)
basketRegion.Add(view)
End Sub
So basketRegion is the region in my ItemsControl as specified above. This region is supposed to hold my basketDetailsViews..

WPF ListView Binding with UpdateSourceTrigger set to explicit strange behaviour

I have a ListView with different DataTemplates set up to bind. I want to update some of the columns (mix of textblock and progress bar) when I call UpdateSource() on a bindingexpression. I also want to update 1 of the columns when the property is changed which it is bound too.
I was able to get the PropertyChanged behaviour to work. But whenever I change the property of one of the other columns they update straight await, instead of on the UpdateSource call. It would appear that its ignoring the UpdateSourceTrigger which is set in the xaml and is using the default behaviour.
I have a class which implements the INotifyPropertyChanged interface.
The xaml for the column I want to update explicitly looks like this:
<GridViewColumn Width="300" Header="Percentage" DisplayMemberBinding="{Binding Percentage, UpdateSourceTrigger=Explicit}" />
And the xaml for one which I want to update on property change:
<GridViewColumn Header="Status" Width="150" DisplayMemberBinding="{Binding Status, UpdateSourceTrigger=PropertyChanged}" />
My binding is set originally like so:
Binding downloadBinding = new Binding();
downloadBinding.Source = _downloads;
ListDownloads.SetBinding(ListView.ItemsSourceProperty, downloadBinding);
If I execute the following code:
_downloads[0].Percentage += 0.3;
_downloads[0].FileSize = 700.00;
_downloads[1].Percentage += 10;
The column percentage column is updated straight away, but I would expect it to wait for the call on UpdateSource().
My code for updating the source is:
BindingExpression be = ListDownloads.GetBindingExpression(ListView.ItemsSourceProperty);
be.UpdateSource();
Am I missing something? I can't find anything online or in a book about why this is happening.
Cheers
I think you're confusing the source and the target... the source is your _downloads collection, the target is the GridViewColumn. The UpdateSourceTrigger property controls when the source is updated by the control, but I assume your grid it not editable, so you don't need to use this property.
The update of the target is always immediate, there is no UpdateTargetTrigger property...

How to do simple Binding in 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.

Resources