Windows Vista Forums
Vista Forums Home Join Vista Forums Windows 7 Forum Vista Tutorials Tags
Welcome to Windows Vista Forums. Our forum is dedicated to helping you find solutions with any problems, errors or issues you are experiencing with Windows Vista. The Vista forum also covers news and updates and has an extensive Windows Vista tutorial section that covers a wide range of tips and tricks.

Go Back   Vista Forums > Misc Newsgroups > Avalon

Vista - How to bind to a DataRelation in a DataSet

 
 
Old 10-19-2006   #1 (permalink)
jmagaram


 
 

How to bind to a DataRelation in a DataSet

I am trying to display a list of people, and for each person I want to show
their corresponding phone numbers. This should be straightforward but it
doesn’t work when a Person’s FullName changes. My dataset has two tables,
shown below. There is a cascading foreign key DataRelation called
FK_Person_Phones. The primary key of each table spans all of its columns.

Person (FullName)
PersonWithPhone (FullName, Phone)

I then create a DataView on the Person table and assign it to the
ItemsSource of listBox1. I also assign the underlying DataSet as the
DataContext of listBox1. Here’s the relevant Xaml:

<ListBox ItemTemplate="{StaticResource personTemplate}" Name="listBox1" />

<DataTemplate x:Key="phoneTemplate">
<StackPanel Orientation="Horizontal" >
<TextBox Text="{Binding Path='FullName'}"></TextBox>
<TextBox Text="{Binding Path='Phone'}"></TextBox>
</StackPanel>
</DataTemplate>

<DataTemplate x:Key="personTemplate">
<StackPanel Orientation="Vertical">
<TextBox Text="{Binding Path='FullName'}"></TextBox>
<ListBox ItemTemplate="{StaticResource phoneTemplate}"
ItemsSource="{Binding Path='FK_Person_Phones'}"></ListBox>
</StackPanel>
</DataTemplate>

This all works fine when I pre-populate the dataset. It works when I add
people. It works when I add phone numbers for any person that was in the
original dataset, or for any person subsequently added - as long as I haven’t
changed their original name. BUT – AND HERE IS THE PROBLEM - if I change the
name of any person in the Person table the Xaml stops showing their
corresponding phone numbers even though the underlying data set reflects the
cascading update. I was under the assumption that by binding to the foreign
key relation I would always see that parent’s child rows. But it seems as
though once the child view is instantiated via the DataRelation the filter on
this view is not updated when the parent’s primary key changes – it always
tries to show the phone numbers corresponding to the person’s original name.
HOW CAN I ALWAYS SHOW EACH PERSON’S CORRESPONDING PHONE NUMBERS EVEN WHEN
THEIR NAME CHANGES?


My System SpecsSystem Spec
Old 10-26-2006   #2 (permalink)
Bart Mermuys


 
 

Re: How to bind to a DataRelation in a DataSet

Hi,

"jmagaram" <jmagaram@discussions.microsoft.com> wrote in message
news:96CD933D-70FE-41C7-A89E-4C9C70FB7233@microsoft.com...
>I am trying to display a list of people, and for each person I want to show
> their corresponding phone numbers. This should be straightforward but it
> doesn't work when a Person's FullName changes. My dataset has two tables,
> shown below. There is a cascading foreign key DataRelation called
> FK_Person_Phones. The primary key of each table spans all of its columns.
>


DataView personView = ... ;
DataRowView personRowView = personView[0];

DataView childPhonesView = (DataView) personRowView["'FK_Person_Phones"];

The above code illlustrates that the parent DataRowView does have a "column"
that returns a child DataView. But you are right there is a problem. The
child DataView returned has a fixed set of parent keys, which will not get
updated. But that's not the real problem.

The real problem is when the parent key changes the parent DataRowView will
fire a PropertyChanged but only for the key column, when the key changes the
child view should be re-acquired. The child view will only be re-acquired
if PropertyChanged would also fire for the the relation-column, but it
doesn't.

So it's the lack of the right event that causes the problem. Somehow you
need to refresh ItemsSource when the name changes, but after having a look
this ain't easy, the problem is the DataRowView and hacking into it doesn't
seem to be an option. And for some other unknown reason calling
UpdateTarget doesn't work even though the parent row at that point returns
the correct child DataView.

So I ended up with a workaround involving a MultiBinding. MultiBinding
allows us to bind to multiple columns. Suppose we bind to name and
FK_Person_Phones then the IMultiValueConverter.Convert will be invoked when
the name changes, unfortenately FK_Person_Phones is still not refreshed (
lack of event ). So that won't work. But if the MultiBinding would be
composed of an empty path Binding and a name Binding, then the converter
will be invoked when name changes and we'll have access to the parent
DataRowView (because of the empty path binding) and we can pass the
FK_Person_Phone through ConverterParameter.


Window1.xaml
----------------
....
<Window.Resources>
<src:GetChildView x:key="GetChildView" />

<DataTemplate x:Key="phoneTemplate">
<StackPanel Orientation="Horizontal" >
<TextBox Text="{Binding Path='FullName'}"></TextBox>
<TextBox Text="{Binding Path='Phone'}"></TextBox>
</StackPanel>
</DataTemplate>

<DataTemplate x:Key="personTemplate">
<StackPanel Orientation="Vertical">
<TextBox Text="{Binding Path='FullName'}"></TextBox>
<ListBox ItemTemplate="{StaticResource phoneTemplate}" >
<ItemsSource>
<MultiBinding Converter={StaticResource GetChildView}
ConverterParameter = "FK_Person_Phones" >
<Binding Path="" />
<Binding Path="FullName"/>
</MultiBinding>
</ItemsSource>
</ListBox>
</StackPanel>
</DataTemplate>
</Window.Resources>
....

<!-- set the DataContext to DataView in code behind -->
<ListBox Name="listBox1"
ItemTemplate="{StaticResource personTemplate}"
ItemsSource={Binding} />
....

GetChildView.cs
-----------------
public class GetChildView : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
return ((DataRowView)values[0])[(string)parameter];
}

public object[] ConvertBack(object value, Type[] targetTypes, object
parameter, System.Globalization.CultureInfo culture)
{
throw new Exception("The method or operation is not implemented.");
}
}


HTH,
Greetings




My System SpecsSystem Spec
Old 11-07-2006   #3 (permalink)
jmagaram


 
 

Re: How to bind to a DataRelation in a DataSet

Thanks. Very very helpful.

"Bart Mermuys" wrote:

> Hi,
>
> "jmagaram" <jmagaram@discussions.microsoft.com> wrote in message
> news:96CD933D-70FE-41C7-A89E-4C9C70FB7233@microsoft.com...
> >I am trying to display a list of people, and for each person I want to show
> > their corresponding phone numbers. This should be straightforward but it
> > doesn't work when a Person's FullName changes. My dataset has two tables,
> > shown below. There is a cascading foreign key DataRelation called
> > FK_Person_Phones. The primary key of each table spans all of its columns.
> >

>
> DataView personView = ... ;
> DataRowView personRowView = personView[0];
>
> DataView childPhonesView = (DataView) personRowView["'FK_Person_Phones"];
>
> The above code illlustrates that the parent DataRowView does have a "column"
> that returns a child DataView. But you are right there is a problem. The
> child DataView returned has a fixed set of parent keys, which will not get
> updated. But that's not the real problem.
>
> The real problem is when the parent key changes the parent DataRowView will
> fire a PropertyChanged but only for the key column, when the key changes the
> child view should be re-acquired. The child view will only be re-acquired
> if PropertyChanged would also fire for the the relation-column, but it
> doesn't.
>
> So it's the lack of the right event that causes the problem. Somehow you
> need to refresh ItemsSource when the name changes, but after having a look
> this ain't easy, the problem is the DataRowView and hacking into it doesn't
> seem to be an option. And for some other unknown reason calling
> UpdateTarget doesn't work even though the parent row at that point returns
> the correct child DataView.
>
> So I ended up with a workaround involving a MultiBinding. MultiBinding
> allows us to bind to multiple columns. Suppose we bind to name and
> FK_Person_Phones then the IMultiValueConverter.Convert will be invoked when
> the name changes, unfortenately FK_Person_Phones is still not refreshed (
> lack of event ). So that won't work. But if the MultiBinding would be
> composed of an empty path Binding and a name Binding, then the converter
> will be invoked when name changes and we'll have access to the parent
> DataRowView (because of the empty path binding) and we can pass the
> FK_Person_Phone through ConverterParameter.
>
>
> Window1.xaml
> ----------------
> ....
> <Window.Resources>
> <src:GetChildView x:key="GetChildView" />
>
> <DataTemplate x:Key="phoneTemplate">
> <StackPanel Orientation="Horizontal" >
> <TextBox Text="{Binding Path='FullName'}"></TextBox>
> <TextBox Text="{Binding Path='Phone'}"></TextBox>
> </StackPanel>
> </DataTemplate>
>
> <DataTemplate x:Key="personTemplate">
> <StackPanel Orientation="Vertical">
> <TextBox Text="{Binding Path='FullName'}"></TextBox>
> <ListBox ItemTemplate="{StaticResource phoneTemplate}" >
> <ItemsSource>
> <MultiBinding Converter={StaticResource GetChildView}
> ConverterParameter = "FK_Person_Phones" >
> <Binding Path="" />
> <Binding Path="FullName"/>
> </MultiBinding>
> </ItemsSource>
> </ListBox>
> </StackPanel>
> </DataTemplate>
> </Window.Resources>
> ....
>
> <!-- set the DataContext to DataView in code behind -->
> <ListBox Name="listBox1"
> ItemTemplate="{StaticResource personTemplate}"
> ItemsSource={Binding} />
> ....
>
> GetChildView.cs
> -----------------
> public class GetChildView : IMultiValueConverter
> {
> public object Convert(object[] values, Type targetType, object parameter,
> System.Globalization.CultureInfo culture)
> {
> return ((DataRowView)values[0])[(string)parameter];
> }
>
> public object[] ConvertBack(object value, Type[] targetTypes, object
> parameter, System.Globalization.CultureInfo culture)
> {
> throw new Exception("The method or operation is not implemented.");
> }
> }
>
>
> HTH,
> Greetings
>
>
>
>
>

My System SpecsSystem Spec
 

Thread Tools


Similar Threads
Thread Forum
bind services and clients Vista General
How to bind to AD without displaying the Distinguished Name PowerShell
Winforms User Controls - How do I bind those to a dataset on the host form .NET General
in a bind Vista mail


Vista Forums is an independent web site and has not been authorized,
sponsored, or otherwise approved by Microsoft Corporation.
"Windows Vista", the Start Orb, and related materials are trademarks of Microsoft Corp.
© Designer Media Ltd

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46