2

I have a UserControl (AgreementDetails) in WPF with the following DependencyProperty and function:

// UserControl AgreementDetails
    public int AgreementID
        {
            get { return Convert.ToInt32(GetValue(AgreementIDProperty)); }
            set { SetValue(AgreementIDProperty, value); }

        }

    public static readonly DependencyProperty AgreementIDProperty = DependencyProperty.Register("AgreementID", typeof(int), typeof(UC1001_AgreementDetails_View), new PropertyMetadata(null));

    private void UserControl_Loaded(object sender, RoutedEventArgs e)
    {
        int id = AgreementID;

        if (id > 0)
        {
            GetData();
            SetBindingContext();
            this.Visibility = System.Windows.Visibility.Visible;
        }
        else
        {
            this.Visibility = System.Windows.Visibility.Collapsed;
        }
    }

    private void GetData()
    {
        ConsultantServiceClient client = new ConsultantServiceClient();
        _contract = new UC1001_ActiveAgreementContract();
        _contract = client.GetAgreementDetailsByAgreementID(AgreementID);
    }

    private void SetBindingContext()
    {
        this.DataContext = _contract;
    }

I use this UserControl to show as a tooltip in another UserControl (Dashboard) where I set the AgreementID property:

// Dashboard    
<Setter Property="DataGridCell.ToolTip">
      <Setter.Value>
             <my:UC1001_AgreementDetails_View Background="#FFF" Opacity="0.88" AgreementID="{Binding Months[9].AgreementID}"/>
      </Setter.Value>
</Setter>

In AgreementDetails, I use the AgreementID to get some data from the database to show in the UserControl. The first time I do this, everything goes smooth. But when I set the incoming WCF DataContract as the datacontext in AgreementDetails, the AgreementID property resets to 0, so the second call will not work because obviously I do not have an agreement with AgreementID = 0. I checked and the AgreementID resets in the SetBindingContext(); method after the DataContext is set.

How can I make it so the AgreementID property will not reset after I set a new dataContext in AgreementDetails??

More information can be provided if wanted.

EDIT: I now have the following code:

// Dependency properties
 public int AgreementID
 {
    get { return (int)GetValue(AgreementIDProperty); }
    set { SetValue(AgreementIDProperty, value); }
 }

 public UC1001_ActiveAgreementContract AgreementDetailsContract
 {
    get { return (UC1001_ActiveAgreementContract)GetValue(AgreementDetailsContractProperty); }
    set { SetValue(AgreementDetailsContractProperty, value); }

 }

    public static readonly DependencyProperty AgreementIDProperty = DependencyProperty.Register("AgreementID", typeof(int), typeof(UC1001_AgreementDetails_View), new PropertyMetadata(null));
    public static readonly DependencyProperty AgreementDetailsContractProperty = DependencyProperty.Register("AgreementDetailsContract", typeof(UC1001_ActiveAgreementContract), typeof(UC1001_AgreementDetails_View), new PropertyMetadata(null));

    private void UserControl_Loaded(object sender, RoutedEventArgs e)
    {
        int id = AgreementID;

        if (id > 0)
        {
            GetData();
            SetBindingContext();
            this.Visibility = System.Windows.Visibility.Visible;
        }
        else
        {
            this.Visibility = System.Windows.Visibility.Collapsed;
        }
    }

    private void GetData()
    {
        ConsultantServiceClient client = new ConsultantServiceClient();
        AgreementDetailsContract = client.GetAgreementDetailsByAgreementID(AgreementID);
    }

    private void SetBindingContext()
    {
       this.DataContext = AgreementDetailsContract;
    }

I still have the the problem that the AgreementID resets to 0 after the DataContext is set.

Also when I use the following statement to bind, I get an empty label:

<Label Content="{Binding RelativeSource={RelativeSource Self}, Path=AgreementDetailsContract.EndClientName}" />

SOLVED:

I removed the SetDataBinding() method so the Binding doesn't reset my DependencyProperty, and for the Binding of my labels I used the following Binding (instead of RelativeSource Self):

 <Label Content="{Binding ElementName=AgreementDetails, Path=AgreementDetailsContract.EndClientName}" Grid.Column="1" Grid.Row="1" Height="28" HorizontalAlignment="Left" Margin="11,0,0,0" Name="_labelEindklant" VerticalAlignment="Top" />

ElementName=AgreementDetails is the name of my UserControl. Strange enough with {RelativeSource Self} it didn't work...

Jelle Capenberghs
  • 794
  • 2
  • 14
  • 30
  • So you set the DataContext of your *second* UserControl to the DataContract? And that DataContract definitely has a property at the path `Months[9].AgreementID` with a non-zero value? – Tim Rogers Oct 17 '11 at 08:46
  • "But when I set the incoming WCF DataContract as the UserControl's datacontext, the AgreementID property resets to 0" I need to know what is the AgreementID value on the interface when you do the above. Does it update to 0 too? – Zahid Sattar Oct 17 '11 at 08:51
  • The two UserControls have two different contracts as its dataContext. The problem is that the AgreementID value resets to 0 after the DataContext is set at the tooltip UserControl – Jelle Capenberghs Oct 17 '11 at 08:54
  • And have you checked that the tooltip DataContract definitely has a property at the path Months[9].AgreementID with a non-zero value? – Tim Rogers Oct 17 '11 at 09:17
  • The tooltip DataContract only uses the AgreementID as a parameter to get the right Agreement. I guess I don't really understand your question. I shall put some more code in my question so you can better understand the problem. – Jelle Capenberghs Oct 17 '11 at 10:08

1 Answers1

1

When you set the datacontext in your Usercontrol, you are actually resetting the data context in the parent control too (Dashboard). It's the same context. Because of this your Agreement ID is no longer in the context and so gets reset.

Edit: Actually I didn't word that very well. You're not affecting the data context in Dashboard, but you ARE affecting the data context used by the AgreementId binding declared in that control. The binding is declared in the Dashboard control, but the binding is actually looking in the data context of the child control, which you are resetting.

See my similar question here: Setting DataContext within UserControl is affecting bindings in parent

EDIT: Here is what I mean:

// UserControl AgreementDetails
public int AgreementID
{
    get { return Convert.ToInt32(GetValue(AgreementIDProperty)); }
    set { SetValue(AgreementIDProperty, value); }
}

//The new property to bind to instead of DataContext
public UC1001_ActiveAgreementContract Agreement
{
    get { return (UC1001_ActiveAgreementContract)GetValue(AgreementProperty); }
    private set { SetValue(AgreementProperty, value); }
}

public static readonly DependencyProperty AgreementIDProperty = DependencyProperty.Register("AgreementID", typeof(int), typeof(UC1001_AgreementDetails_View), new PropertyMetadata(null));

//should really be readonly dependency property
public static readonly DependencyProperty AgreementProperty = DependencyProperty.Register("Agreement", typeof(UC1001_ActiveAgreementContract), typeof(UC1001_AgreementDetails_View), new PropertyMetadata(null));**

private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
    int id = AgreementID;

    if (id > 0)
    {
        GetData();
        SetBindingContext();
        this.Visibility = System.Windows.Visibility.Visible;
    }
    else
    {
        this.Visibility = System.Windows.Visibility.Collapsed;
    }
}

private void GetData()
{
    ConsultantServiceClient client = new ConsultantServiceClient();
    _contract = new UC1001_ActiveAgreementContract();
    _contract = client.GetAgreementDetailsByAgreementID(AgreementID);
}

private void SetBindingContext()
{
    this.Agreement = _contract;
}

Then in your AgreementDetails.xaml, you probably have something like:

<!-- Bound to property in DataContext -->
<TextBlock Text={Binding SomeContractProperty} />

which binding needs to change to:

<!-- Bound to new property on UC1001_AgreementDetails_View (UserControl) -->
<TextBlock Text={Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UC1001_AgreementDetails_View}}, Path=Agreement.SomeContractProperty} />
Community
  • 1
  • 1
GazTheDestroyer
  • 20,722
  • 9
  • 70
  • 103
  • The explanation makes sense. But I'm afraid I can't get a solution because the datacontext is a WCF datacontract in the "child"-usercontrol which is set at runtime, how do you suggest I implement a working solution? – Jelle Capenberghs Oct 17 '11 at 13:17
  • You need to stop setting the DataContext in the child. Instead expose some other property in the child control (Agreement?) that is an instance of your WCF datacontract, and bind to that instead. You can then set this instance when AgreementId changes, instead of setting the DataContext. – GazTheDestroyer Oct 17 '11 at 13:25
  • I made another DependencyProperty of the DataContract type I use as DataContext in the child UserControl, but how can I pass it in my parent UserControl since I only declare it in the child UserControl? – Jelle Capenberghs Oct 17 '11 at 13:44
  • Why do you need it in your parent? The only thing the parent needs access to is the Id. Once that is set you create your new property from WCF and your child control XAML can bind to it. – GazTheDestroyer Oct 17 '11 at 13:48
  • So what you are trying to say, isn't it the same that I do now in my GetData() and SetDataBindings() methods? That's how I understand it, actually... My parent has the AgreementID the child needs. I pass the ID to the child using a DependencyProperty. In the child, I get the right data from my WCF host in a DataContract, and then I bind that DataContract as DataSource to my child. This binding causes the AgreementID to disappear in the Parent because due to the new binding in the child, the binding in the parent resets. – Jelle Capenberghs Oct 17 '11 at 13:56
  • Yes, that's what I mean. It's exactly the same as you're doing now. The only difference is that instead of using DataContext to expose the WCF contract to your child XAML, you're using your new DependencyProperty instead. The parent code remains exactly the same. – GazTheDestroyer Oct 17 '11 at 14:15
  • I've updated my main answer with some example code of what I mean – GazTheDestroyer Oct 17 '11 at 14:30
  • I tried with your code but I still have the same problem. See my updated question above – Jelle Capenberghs Oct 18 '11 at 08:09
  • You are still setting your DataContext: (this.DataContext = AgreementDetailsContract;) – GazTheDestroyer Oct 18 '11 at 08:18
  • If I don't set it my labels also stay empty because there is no Binding. I am sorry, but I feel like I'm missing something obvious here :) – Jelle Capenberghs Oct 18 '11 at 08:21
  • I found the solution and put it in my question above! – Jelle Capenberghs Oct 18 '11 at 08:42