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
17/07/2008 15:41:24
 
 
To
17/07/2008 13:13:13
General information
Forum:
ASP.NET
Category:
Windows Presentation Foundation (WPF)
Miscellaneous
Thread ID:
01331472
Message ID:
01332076
Views:
10
Well...The first problem I had was setting the ItemsSource in XAML. I couldn't figure it out, so I do it in the form constrctor. Seeing more of your code, I think I see a slightly diffferent structure... As far as my ComboBox goes, it is not in a UserControl, it's just a plain UI control in a HeaderedContentControl (I wonder where I learned about that), that is also in a StackPanel, that is also in a Grid. I tried to set ItemsSource="{Binding Path=custs, ElementName=______ (don't know what to put here).

So, in code-behind, I set the DataContext of gridMain to a Job, and I also set the ItemsSource on the ComboBox to the full list of Customer objects (the "custs" collection). I really want to figure out setting the ItemsSource in XAML, but haven't so far.
   <Grid x:Name="gridMain" Height="454" Width="591">
        <Grid.RowDefinitions>
            <RowDefinition Height="50"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>

        <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, Mode=TwoWay}"
                              SelectionChanged="dropdownCustomer_SelectionChanged"                              
                              />
                </HeaderedContentControl>
              <StackPanel Orientation="Horizontal">
                  <TextBlock Text="Ph: " Margin="10,0,0,0"/>
                  <TextBlock Text="{Binding Path=Customer.phone}" />
               </StackPanel>
            </StackPanel>
<..... />

</Grid>
Full code:
namespace wpf2
{
    public partial class WindowJobEdit : Window
    {
        private string _JobNo;

        DataClasses1DataContext ctx = new DataClasses1DataContext();
        Job JobToEdit;
        public IQueryable<Customer> custs;

        public WindowJobEdit(string JobNo)
        {

            custs = from c in ctx.Customers
                         select c;
            
            InitializeComponent();
            
            dropdownCustomer.ItemsSource = custs;  //Set the UI ComboBox list choices

            GetJobToEdit(JobNo);

            gridMain.DataContext = JobToEdit;
  
        }


        public void GetJobToEdit(string JobNo)
        {
            _JobNo = JobNo;

            if (JobNo != null)
            {
                JobToEdit = ctx.Jobs.Single(o => o.job_num == JobNo);
            }
        }

        private void dropdownCustomer_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ComboBox SendingObject = (ComboBox)sender;

            if (JobToEdit != null)
            {
                JobToEdit.Customer = (Customer)SendingObject.SelectedItem;
            }
        }
However, that is not really the issue with the greater goal here of updating the Customer reference in a Job from the XAML binding, so I've just been letting the ItemsSource thing slide for now. But I'm certainly curious to figure it out.

Also, is your DataStores a collection of strings? I notice you are not having to use DisplayMemberValue and SelectedItemPath. My ItemsSource is a collection of Customer objects, so I have to specify which field on the Customer object is what part. I see that you are using SelectedValue but not the other two.


So you are able to point the ItemsSource to a Path on your UserControl, but what do I need to point to in order to get at the public custs collection?




>>Hope I'm not bothering you here
>
>Not at all.
>
>What you learned fits with what I've seen.
>
>My example was working code that I pulled from one of my forms I changed a few things to fit with your dojects. So... the question is why didn't it work?
>
>
<ComboBox ItemsSource="{Binding Path=Customers, ElementName=thisControl}"
>                       SelectedValue="{Binding Path=Customer, Mode=TwoWay}" >
>      <ComboBox.ItemTemplate>
>        <DataTemplate>
>          <TextBlock Text="{Binding Path=company}"/>
>        </DataTemplate>
>      </ComboBox.ItemTemplate>
></ComboBox>
>
>From your example ItemsSource does appear to be a collection of Customer objects, so that looks right.
>
>It also looks like your DataContext is set to JobToEdit so that also looks right. Are you getting a binding error in the output window?
>
>Here's the actual code on my system... maybe it will help:
>
>C#
  public partial class cdsJobInfoPage : UserControl
>    {
>    private cdsJobObject       JobContext;
>    public IEnumerable<cdsDataStore> DataStores { get; set; }
>    public cdsJobInfoPage(cdsJobObject job)
>      {
>      JobContext  = job;
>      DataContext = job.Entity;  // the entity here is my JobToEdit
>      DataStores  = job.GetDataStores();
>      InitializeComponent();
>      }
>
>XAML
<UserControl ... Name="ucJobInfo"> ...
>    <ComboBox Grid.Row="3"
>              Grid.Column="1"
>              Name="cmbDataStores"
>              Height="20"
>              ItemsSource="{Binding Path=DataStores, ElementName=ucJobInfo}"
>              SelectedValue="{Binding Path=cdsDataStore, Mode=TwoWay}" >
>      <ComboBox.ItemTemplate>
>        <DataTemplate>
>          <TextBlock Text="{Binding Path=Name}"/>
>        </DataTemplate>
>      </ComboBox.ItemTemplate>
>    </ComboBox>
>
>My jobs are data processing projects so this sets the root of the folder tree where the jobs data files will be stored.
>
>See if you find anything in that. And if you don't let me know exactly what it is doing and not doing.
>
>John
>
>>Hope I'm not bothering you here, but this is a MAJOR hurdle... I'm pulling my hair out over this one!! Spent HOURS today on trying to update the Job.cust_num via pure XAML binding, and I have not accomplished it yet (without using code-behind on SelectionChanged).
>>
>>Here's a few things I learned (could be wrong on some of this, so please feel free to correct me)
>>
>>With the Linq-to-Sql modelling and the Association between Job.cust_num and Customer.custno like we are hashing around with here, you CANNOT set the cust_num field of the Job object directly. You get this error in the output window: "A first chance exception of type 'System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException' occurred in wpf2.exe"
>>
>>And, naturally, the very XAML that I wrote for my UI is causing said error every time I make a selection in the ComboBox, as it is trying set Job.cust_num to the value of the selected item, as the binding instructions have told it to.
>>
>>
>>          <ComboBox x:Name="dropdownCustomer" IsSynchronizedWithCurrentItem="True" AllowDrop="True"
>>                    DisplayMemberPath="company" SelectedValuePath="custno"
>>                    SelectedValue="{Binding Path=cust_num, Mode=TwoWay}"
>>             />
>>
>>
>>
>>So, we have already learned that you must change the Customer object within the Job to accomplish what we are after (as far as I have learned from more than one place, this is the way it must be done).
>>
>>Therefore, I did get it working with the SelectionChanged method and some simple code-behind:
>>
>>
>>          <ComboBox x:Name="dropdownCustomer" IsSynchronizedWithCurrentItem="True" AllowDrop="True"
>>                    DisplayMemberPath="company" SelectedValuePath="custno"
>>                    SelectedValue="{Binding Path=cust_num, Mode=TwoWay}"
>>                    SelectionChanged="dropdownCustomer_SelectionChanged"
>>            />
>>
>>
>>Code-behind:
>>
>>    private void dropdownCustomer_SelectionChanged(object sender, SelectionChangedEventArgs e)
>>    {
>>        ComboBox SendingObject = (ComboBox)sender;
>>
>>        if (JobToEdit != null) // must check... is null at form launch
>>            JobToEdit.Customer = (Customer)SendingObject.SelectedItem;
>>        }
>>    }
>>
>>
>>
>>By the way, even though the Customer object is from a totally different source context, this does work! (I had heard that objects that are EXACTLY the same are handled this way by the CLR.)
>>
>>Only thing I still don't like is: Because of the SelectedItem="{Binding Path=cust_num}" in the XAML (which is necessary to point the ComboBox to the correct Customer at the launching of the form), although you do not get a run-time error, and everything in the app works exactly like I want, BUT, if you look at the Output Window it is giving that stupid "A first chance exception of type 'System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException' occurred in wpf2.exe" error with every selection of the ComboBox. I need to figure out how to synch up without SelectedValue.
>>
>>I have not found one single example on the internet that addresses this matter thoroughly enough to show what to do. Most examples are based on ad-hoc made-on-the-fly object lists that work good for demo, and they sure make it look easy. Let's see 'em do it against real data from a Linq-to-Sql model.
>>
>>
>>
>>I did experiment with your suggestion on trying to bind SelectedValue to a Customer reference, but I could not get it wired the right way to make it work.
>>
>>
>>
>>
>>
>>>>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
>>>
>>>
Previous
Next
Reply
Map
View

Click here to load this message in the networking platform