WPF Databinding issue - wpf

I'm using a RadGridView (Telerik). I'm trying to make a column editable only for certain rows, but what I'm trying doesn't seem to be working and I'm not sure how to do it.
My grid is this:
<telerik:RadGridView HorizontalAlignment="Left" Margin="12,12,12,12" Name="radGridView1" VerticalAlignment="Top" ItemsSource="{Binding FeedList}" ShowGroupPanel="False" AutoGenerateColumns="False" ShowInsertRow="True" EditTriggers="Default">
<telerik:RadGridView.Columns>
<telerik:GridViewDataColumn Header="Feed" DataMemberBinding="{Binding Path=Name}" Width="150" IsReadOnly="{Binding Path=ReadOnly}" />
<telerik:GridViewDataColumn Header="Url" DataMemberBinding="{Binding Path=Url}" Width="*"/>
</telerik:RadGridView.Columns>
</telerik:RadGridView>
The bound object has a property, but the Path for the IsReadOnly binding is relative to the DataContext for the form and not the bound object. How would I make it relative to the bound object in this case?

In case anyone comes across this on a search. The answer is the GridView's datacontext is bound to the collection it's displaying and doesn't have access to the Window or UserControl's datacontext.
Thomas Levesque has a blog entry on the subject. He puts together a BindingProxy class that you can use to pass in the datacontext to the radgridview.
http://www.thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/

Intellisense must have been messed up. Somehow missed the IsReadOnlyBinding property of GridViewDataColumn, which does exactly what I want. Not sure why IsReadOnly couldn't do it, though.

Related

DataBinding in CellEditDataTemplate not working when use ElementName

I have tried to update ItemSource of RadComboBox using ElementName property in Binding but when I use RelativeSource it is working as expected.
What is the difference.Can anyone please tell me.
<telerik:RadGridView Name="DesiredCapabilitiesGrid" RowIndicatorVisibility="Collapsed" AllowDrop="False" CanUserDeleteRows="True ShowGroupPanel="False" Height="Auto" Width="Auto"ItemsSource="{Binding DesiredCapabilities,Mode=TwoWay}"
GroupRenderMode="Flat" NewRowPosition="Bottom" Loaded="DesiredCapabilitiesGrid_Loaded">
<telerik:RadGridView.Columns>
<telerik:GridViewDataColumn Header="Property Names" Width="2*" IsSortable="True" DataMemberBinding="{Binding DesiredCapabilityName}">
<telerik:GridViewDataColumn.CellEditTemplate>
<DataTemplate>
<telerik:RadComboBox ItemsSource="{Binding Path=DataContext.ConsiderDesiredCapabilites,ElementName="DesiredCapabilitiesGrid"}" IsEditable="True"></telerik:RadComboBox>
</DataTemplate>
</telerik:GridViewDataColumn.CellEditTemplate>
</telerik:RadGridView.Columns>
</telerik:RadGridView>
There is no element named DesiredCapabilitiesGrid in the same namescope as the RadComboBox in the CellEditTemplate. That's why the binding fails.
The RadComboBox is added to the visual tree and has visual ancestors though. That's why setting a RelativeSource work. Please refer to the link for more information about namescopes.

Binding Data Table to DataGrid using View Model

I have a requirement where I need to display data from a DataTable as it is, i.e. no editing required for the cells. The other requirement is that I need to display Combobox as header of Each Column.
Secondly, The First Column needs to be a checkbox, checking which grays out the row. I thought it should be feasible with DataGrid, but I am not sure, as I am not able to find a way to do it.
Can please somebody help me out. Please note that I wish to do it the MVVM way and not write code in xaml.cs
Eagerly looking forward for a response.
Thanks in advance.
EDIT : code added though its not much...
.xaml
<DataGrid HorizontalAlignment="Left" Margin="0,274,0,0" VerticalAlignment="Top" Height="321" Width="981" AutoGenerateColumns="True" ItemsSource="{Binding Path=UploadedProductData, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}">
<DataGrid.Columns>
<DataGridTemplateColumn CanUserReorder="False" CanUserResize="False">
<DataGridTemplateColumn.HeaderTemplate>
<DataTemplate>
<ComboBox HorizontalAlignment="Right" VerticalAlignment="Top" Width="100"/>
</DataTemplate>
</DataGridTemplateColumn.HeaderTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="" VerticalAlignment="Top"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
In the view model of main window -
DataTable _uploadedProductData;
public DataTable UploadedProductData
{
get { return _uploadedProductData; }
set
{
_uploadedProductData = value;
}
}
The above is the property.
In the xaml.cs - I set the above property - on some button event
ViewModel.UploadedProductData = dt;
Everything that you stated in your requirements is entirely possible in WPF. Most things are possible with WPF. Now that you have provided some code, I can see that you are missing the required INotifyPropertyChanged interface... click the link for help with this. You will need to implement this to have the UI update after property values have changed... do you see how including a code example is already working for you?
It is indeed possible to create a DataTemplate to define what is seen in the Header section of a DataGrid. You can think of a DataTemplate as a tiny view for a particular piece of data and you can set a DataTemplate to the Header using the DataGrid.RowHeaderTemplate property as you have almost got:
<DataGrid>
<DataGrid.RowHeaderTemplate>
<DataTemplate>
<!--Define how you want the header to look here-->
<DataTemplate>
</DataGrid.RowHeaderTemplate>
</DataGrid>
Now, when it comes to binding to the cells, it really depends on the object that you are using. In WPF, it is customary (but not compulsory) to create data type objects that represent your data accurately. In your case, I'm going to assume that you will just use your DataTable object and so it is the column names that are important.
It is best to use the DataGridTextColumn column for displaying text and you could also choose to use the DataGridTextColumn.HeaderTemplate instead if you want the Header to be different for different columns:
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Path=ColumnName0}">
<DataGridTextColumn.HeaderTemplate>
<ComboBox HorizontalAlignment="Right" VerticalAlignment="Top" Width="100"/>
</DataGridTextColumn.HeaderTemplate>
</DataGridTextColumn>
<DataGridTextColumn Header="First Name" Binding="{Binding Path=ColumnName1}" />
<DataGridTextColumn Header="Last Name" Binding="{Binding Path=ColumnName2}" />
</DataGrid.Columns>
Now I'm guessing that you're going to ask how to populate the ComboBox.ItemsSource item collection next, but I'm running out of time. For that, I'll refer you to the WPF ComboBox in DataGridTemplateColumn with alternate ItemsSource post and say that if that doesn't help you, you could easily find this information from an internet search.

How do I bind child entity detail fields to text boxes?

My RadGridView is bound to child records via the parent entity's navigation property. Users can edit records in the grid. Now I'd like to also allow editing of child records outside of the grid. After selecting a record in the grid you could edit it using text boxes. I can't seem to find the right binding statement for each text box. My working child grid XAML looks something like this:
<telerik:RadGridView Name="childGrid" ItemsSource="{Binding ChildEntitiesNav, Mode=TwoWay}" IsSynchronizedWithCurrentItem="True" AutoGenerateColumns="False">
<telerik:RadGridView.Columns>
<telerik:GridViewDataColumn DataMemberBinding="{Binding ChildFieldOne}" Header="Child Field One"/>
<telerik:GridViewDataColumn DataMemberBinding="{Binding ChildFieldTwo}" Header="Child Field Two" />
I've added text boxes corresponding to each grid column but I can't get any data to appear. I've tried these text box binding statements:
Text="{Binding Path=ChildEntitiesNav.ChildFieldOne}
and Text="{Binding Path=ChildFieldOne}
I'm using WPF and Entity Framework database first. What is the correct binding statement for editing child detail entities via a parent navigation property?
Thanks in advance.
ANSWER: Andrey's response led me to the solution. I simply needed to bind my text boxes to the grid's SelectedItem (rather than binding to the child entity). I added the grid name as the DataContext to my text box:
<TextBox Name="ChildFieldTextBox" Text="{Binding Path=ChildFieldName, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" DataContext="{Binding ElementName=childGrid, Path=SelectedItem, Mode=TwoWay}" />
These links helped:
Here and here.
Here is an article which may help you. It describes how to bind a control to a property of DataGrid's selected item.
Or you can to add SelectedChildEntityNav property to your ViewModel. The RadGridView declaration will look like this:
<telerik:RadGridView Name="childGrid" IsSynchronizedWithCurrentItem="True" AutoGenerateColumns="False"
ItemsSource="{Binding ChildEntitiesNav, Mode=TwoWay}"
SelectedItem="{Binding SelectedChildEntityNav, Mode=TwoWay}">
After that you're able to bind the textboxes to SelectedChildEntityNav's properties.

How can I access the textbox value which is embeded inside a Silverlight(3.0) Grid?

I have a Silverlight DataGrid control inside which I have a textbox and a button control.
It is as under
<dg:DataGrid x:Name="myGrid" AutoGenerateColumns="False">
<dg:DataGrid.Columns>
<dg:DataGridTemplateColumn Header="Name" Width="100">
<dg:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox Text="{Binding Name}" x:name="txtName"/>
</DataTemplate>
</dg:DataGridTemplateColumn.CellTemplate>
</dg:DataGridTemplateColumn>
<dg:DataGridTemplateColumn Header="Age" Width="100">
<dg:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox Text="{Binding Age}" x:name="txtAge"/>
</DataTemplate>
</dg:DataGridTemplateColumn.CellTemplate>
</dg:DataGridTemplateColumn>
<dg:DataGridTemplateColumn Header="Action" Width="100">
<dg:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button x:Name="btnCilck" Content="Click" Click="btnClick_Click />
</DataTemplate>
</dg:DataGridTemplateColumn.CellTemplate>
</dg:DataGridTemplateColumn>
</dg:DataGrid.Columns>
</dg:DataGrid>
What I want to do is that at runtime I want to fetch the textbox value (txtName) for the row selected.
I mean, say the grid has 10 rows(i.e. 10 textbox's in that particular column; say Column Name) and 10 Buttons in say Action column(let's name it like that).
Now when I click on the 5th rows Click button, I want to get the value from the textbox present in that row.
Thanks in advance.
In the click event handler you can examine the sender's (Button's) DataContext, which will be the item represented by that row and will have the properties Name, Age etc.; you can get the property which is bound to the textbox.
A better design, assuming you designed your app with MVVM, is to have an ICommand in the ViewModel and bind the Button's Command property to that ICommand. In that case you can bind something to the CommandParameter of the button and receive it in the ICommand handler - either the DataContext itself with {Binding} or the actual property you're interested in.
Edit: sorry about going on with the Command bindings, they're not readily available in SL3; there are ways around it though, google it if you're interested. The commanding pattern will much better encapsulate the actions across your application.
There are actually ways to get to the actual contents of the grid cells, but I wouldn't recommend it, as it will come with a lot of overhead and will be fragile in case any of the templates change; it's much better to work with the actual data and leave the controls to do their jobs through bindings.

WPF: ComboBox with selecteditem set make not use of SelectedIndex=0?

Why is the first element in my combobox popup menu not shown in the selected item area of
my combobox , when I use the SelectedItem binding? Without that it is showing up ?? Using
the same code selecteditem + selectedindex that is no problem!
<ComboBox
ItemsSource="{Binding SchoolclassSubjectViewModels}"
SelectedItem="{Binding SelectedSchoolclassSubjectViewModel}"
SelectedIndex="0"
Height="23"
HorizontalAlignment="Left"
Margin="375,13,0,0"
VerticalAlignment="Top"
Width="151">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding SchoolclassName}" />
<TextBlock Text=" " />
<TextBlock Text="{Binding SubjectName}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Well as workaround I used:
SchoolclassSubjectViewModels.Add(schoolclassSubjectVM);
SelectedSchoolclassSubjectViewModel = schoolclassSubjectVM;
and this:
SelectedItem="{Binding SelectedSchoolclassSubjectViewModel,Mode=TwoWay}"
but I would prefer the xaml only way as it should really work.
It is because the reference inside your ItemsSource collection is not the same as the one in your SelectedItem property. I would venture to guess that you are using one object context to query your database for the list of SchoolclassSubject objects which the ItemsSource is bound to, but another context to query the actual data item to which you bind the SelectedItem. Even though the list contains a reference which represents the value held by your object, it is not really the same reference, but a separate instance of the same data.
There are ways to solve this issue, most of them involve using the SelectedValuePath and SelectedValue instead of the SelectedItem properties, but the concrete solution would be different depending on your particular ORM.

Resources