Level Extreme platform
Subscription
Corporate profile
Products & Services
Support
Legal
Français
How do you bind to a property on a reference object?
Message
From
16/07/2008 13:43:34
 
 
To
16/07/2008 13:08:34
General information
Forum:
ASP.NET
Category:
Windows Presentation Foundation (WPF)
Miscellaneous
Thread ID:
01331472
Message ID:
01331735
Views:
6
>Dude, I hope you read this soon!!

I did. <g>

Your catching up to me I learned about this a few weeks ago. What confuses me is I have changing the ID working fine in one of my classes and I don't know why it is working. <g>

What you found was the next thing to try, but let me propose a slightly different solution.
<ComboBox ItemsSource="{Binding Path=Customers, ElementName=thisControl, Mode=TwoWay}"
                       SelectedValue="{Binding Path=Customer, Mode=TwoWay}" >
      <ComboBox.ItemTemplate>
        <DataTemplate>
          <TextBlock Text="{Binding Path=company}"/>
        </DataTemplate>
      </ComboBox.ItemTemplate>
</ComboBox>
Customers is a list of Customer objects.
Customer is Job.Customer (The object not the ID)
company is Customer.company

Since the selected value is the object not the id you should not need the extension to your class.

The one point of uncertainty I have is...

If the Customers list is from a different data context than the Job object... does it work?

(This was a long post and I tried to answer it quickly so hopefully I understood it all correctly.)

John





>>I just learned the most incredible thing... I hope it's a good approach.
>
>When you have this "Job object has a Customer object reference" kind of object model, like you get with the Linq-to-Sql designer, as you know the Job object has a foreign key reference to the customer number, but it also has a reference to a Customer object, right? So, here's what I learned: When you want to change the cust_num that the Job is assigned to, you do NOT change the FK cust_num field on the Job object, instead you UPDATE the Customer object reference on the Job object, and the Linq-to-Sql classes somehow realize what you have done, and it updates the FK cust_num field on the Job object for you when you call context.SubmitChanges(). I was going at it backwards! It makes sense, I guess. I suppose they could have made it work either way, but this is how it seems to work.
>
>I modelled it and it really does work.
>
>I already had my XAML ComboBox pointing to Job.cust_num with SelectedValue="{Binding Path=cust_num}", but that really does not have any affect on the underlying table or the Job object, even with Mode=TwoWay included. It seems to help point the ComboBox to the correct Customer from the ItemsSource when the form is first initialed, but it does not seem to update the Job.cust_num property on the Job object when you make a new selection. However, it does provide a key that I can use to update the Customer reference to a new Customer by using the SelectionChanged="dropdownCustomer_SelectionChanged" setting on the ComboBox in XAML.
>
>Here's my ComboBox XAML:
>
>   <ComboBox x:Name="dropdownJobStatus" IsSynchronizedWithCurrentItem="True" AllowDrop="True"
>                     DisplayMemberPath="company" SelectedValuePath="custno"
>                     SelectedValue="{Binding Path=cust_num}"
>                     SelectionChanged="dropdownCustomer_SelectionChanged" />
>
>
>Noe, in the ComboBox, the ItemsSource is set in code-behind as a collection of Customer objects, so DisplayMemberPath and SelectedValuePath work off of that context, but SelectedValue is linked to the context of the container of the ComboBox, which is the Job object that I am displaying, updating, edit, whatever.
>
>And, in the code-behind for dropdownCustomer_SelectionChanged, you update the Customer object reference of the Job Object, based on the SelectedValue of the ComboBox by getting a new Customer reference to poke into the Job:
>
>
>    private void dropdownJobStatus_SelectionChanged(object sender, SelectionChangedEventArgs e)
>    {
>        ComboBox SendingObject = (ComboBox)sender;
>
>        if (SendingObject.SelectedValue != null)
>        {
>            String SelectedCustomer = SendingObject.SelectedValue.ToString();
>            if (SelectedCustomer != null)
>            {
>                JobToEdit.Customer = ctx.Customers.Single(c => c.custno == SelectedCustomer);
>            }
>        }
>    }
>
>
>
>
>Here's to post I found that taught me this:
>
>http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=3020968&SiteID=1
>
>
>
>
>
>You should be setting the association property instead of the foreign key.
>
>LINQ to SQL objects have both association properties (references or lists of other objects)
>and the key fields that are used to define these associations in the database.
>That means there are at least two different properties on your object that determine this relationship.
>If foriegn key fields and association properties are not kept in agreement, LINQ to SQL will throw this
>exception when you attempt to submit changes since it doesn't know which is the correct value, the one
>in the foreign key field or the one on the other side of the relationship.  The only time a foriegn key
>field is used exclusively as the value is when there is either no association property defined on the
>object using that field as a key or the association property was never assigned a value.
>
>The code-generated objects you are using will automatically keep the foreign keys in sync with any
>association property when you assign the association property a value.  Since they do this, they also know
>that any assignment to a foreign key field that actually changes its value is illegal if the corresponding
>association property has already been set.  That's why the generated property setter throws the exception
>directly, so you get the exception closer to where the bug is.
>
>artist.ContactLink = db.ContactLinks.Single(c => c.Id == someContactLinkId);
>
>
>
>
>Now, this really doesn't seem like Data Binding to me; at least not TwoWay databinding, since I have two write code-behind to do the real work. I can see calling it OneWay, since it will at least drive correct choice in the ItemsSource of the ComboBox based on the Job.cust_num. Maybe real TwoWay can be achieved if you can the ComboBox itsself to update the Job.Customer reference.
>
>Got some more learning to do...
>
>Also, I could not figure out why I cannot use the Customer object reference that comes right from the ItemsSource of the ComboBox. It does get passed into the dropdownJobStatus_SelectionChanged event via the sender object, and surely it can be somehow used as the Customer object reference that I need to poke into the Job object. It gives the old "Object reference not set to an instance of an object." error. It really is a real Customer object type, but it does not like it. What am I missing? It sure would be a sweeter solution that making a Linq cts.Customer.Single(...) call.
>
>
>
>        if (SendingObject.SelectedItem != null)
>        {
>            JobToEdit.Customer = (Customer)SendingObject.SelectedItem;
>        }
>
>
>
>
>
>.
>.
>.
>
>
>
>>I'm Tired... so I'll look this over a bit more tomorrow. I have had problems with the "." in the path at times, but I can't remember if that was just with xceeds datagrid or if I've had trouble in other locations. Glad its working for you. Just A quick WAG on the binding not updating, but try adding Mode=TwoWay on the SelectedValue binding. It's always my first try when they don't update. If that doesn't work we will have to look further into it.
>>
>>The blog post looks very very interesting, I will have to check it out more. If that works, and I assume it will, it's a great find!!!! Thanks!
>>
>>Currently I am having to do a foreach loop when I need an observable collection, so that solution is sweet!
>>
>>John
>>
>>>Actually, this began to work properly. Not sure what I had wrong first time.
>>>
>>>Here's the (simple) structure: The DataContext on the parent container is a Job object, which has a Customer reference, which has a phone poperty. And this actually pops up the right value of the Job.Customer.phone in the UI. I was so happy. It sure seemed logical, and I was confused when it did not work, but now it does. Remember, my Job object is from a Linq query on Linq-to-Sql objects, which use Association attributes to hook up Job and Customer.
>>>
>>>
>>>        <StackPanel x:Name="spHeader" Orientation="Horizontal" Width="Auto" >
>>>            <StackPanel x:Name="spCustomerData">
>>>              <HeaderedContentControl Header="Customer:" Width="150">
>>>                <ComboBox x:Name="dropdownCustomer" IsSynchronizedWithCurrentItem="True" AllowDrop="True"
>>>                          DisplayMemberPath="company" SelectedValuePath="custno" SelectedValue="{Binding Path=cust_num}" SelectionChanged="dropdownCustomer_SelectionChanged" />
>>>              </HeaderedContentControl>
>>>              <StackPanel Orientation="Horizontal">
>>>                  <TextBlock Text="Ph: " Margin="10,0,0,0"/>
>>>                  <TextBlock Text="{Binding Path=Customer.phone}" />
>>>               </StackPanel>
>>>            </StackPanel>
>>>          </StackPanel>
>>>
>>>
>>>Anyway, it works great for DISPLAY, but it is totally un-aware when I use the ComboBox to change the custno of the Job (not a real-world workflow but good for testing how all this stuff works). Here's what I mean... if I select a new value from the ComboBox which is hosting the Customer choices that the Job is assigned to (ItemsSource fed by a different linq query) the custno property is not getting updated on the Job object. So much for Binding!!!
>>>
>>>So, there is something I do not understand about 2-way data binding in WPF and Linq-To-Sql.
>>>
>>>Would you please read this short blog post, and see if this is really the answer: http://blog.lab49.com/archives/1971
>>>
>>>
>>>
>>>
>>>
>>>>>I have a Job object that includes a reference to a customer object that has data about the customer (from Linq-to-Sql call).
>>>>>
>>>>>So, how do I bind to the properties on the Customer reference that is within the Job item which is the DataContext for my ContentControl?
>>>>>
>>>>>For instance, the pseudo path to the phone number is like this:
>>>>>
>>>>>Job.Customer.phone
>>>>>
>>>>>so how do I poiont to that in the XAML?
>>>>>
>>>>>I tried (with no luck):
>>>>>
>>>>>
>>>>>             <TextBlock Text="{Binding Path=Customer.phone}" />
>>>>>
>>>>
>>>>I struggled with that one too, ended up extending the entity class like this:
>>>>
>>>>
public partial class JobItem
>>>>  {
>>>>  public string  Phone { get { return Customer.phone; } }
>>>>  }
>>>>
>>>>If you come up with a better solution let me know.<g>
Previous
Next
Reply
Map
View

Click here to load this message in the networking platform