Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I bind or otherwise get & set a value of a control in a resource?

How can I bind a control inside a usercontrol resource to a property? Alternatively, can I find the control from the code behind and get & set the value from there?

Here is my markup. I've stripped it down to just the relevant part:

Salesmen.xaml:

<UserControl.Resources>
            <ControlTemplate x:Key="EditAppointmentTemplate1" TargetType="local:SchedulerDialog" x:Name="ControlTemplate">
                <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
                    <Grid>
                        <Grid Name="grdTotal" Grid.Row="4" Visibility="{Binding ResourceTypesVisibility}">
                            <TextBox x:Name="totalSalesmen" Grid.Row="0" Grid.Column="1" Margin="3" Width="120" Text="{Binding Parent.totalSalesmen, ElementName=LayoutRoot, Mode=TwoWay}" />
                        </Grid>
                </ScrollViewer>
            </ControlTemplate>
    <Style x:Key="EditAppointmentDialogStyle1" TargetType="local:SchedulerDialog">
        <Setter Property="Template" Value="{StaticResource EditAppointmentTemplate1}" />
    </Style>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White" HorizontalAlignment="Left" Margin="10,10,0,0">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>

    <StackPanel Orientation="Vertical">
        <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" BorderBrush="Transparent">
            <telerik:RadCalendar Name="RadCalendar" SelectedDate="{Binding CurrentDate, ElementName=RadScheduleViewTests, Mode=TwoWay}" IsTodayHighlighted="True"
                         telerik:StyleManager.Theme="Metro" HorizontalAlignment="Left" VerticalAlignment="Top" FirstDayOfWeek="Sunday" Margin="0,0,15,0"
                         SelectionChanged="RadCalendar_SelectionChanged_1"  >
            </telerik:RadCalendar>
        </ScrollViewer>
    </StackPanel>

    <telerik:RadScheduleView Name="RadScheduleViewTests"  MinAppointmentWidth="100" Tag="{Binding Path=Context, ElementName=TestDayPage}"
                             telerik:StyleManager.Theme="Metro" Grid.Column="1" EditAppointmentDialogStyle="{StaticResource EditAppointmentDialogStyle1}"
                             AppointmentCreating="RadScheduleViewTests_AppointmentCreating_1" AppointmentEditing="RadScheduleViewTests_AppointmentEditing_1"
                             AppointmentDeleting="RadScheduleViewTests_AppointmentDeleting_1" FirstDayOfWeek="Sunday" ShowDialog="RadScheduleViewTests_ShowDialog_1"
                             AppointmentEdited="RadScheduleViewTests_AppointmentEdited_1">
        <telerik:RadScheduleView.DragDropBehavior>
            <examiners:CustomDragDropBehaviour/>
        </telerik:RadScheduleView.DragDropBehavior>
        <telerik:RadScheduleView.SchedulerDialogHostFactory>
            <test:CustomScheduleViewDialogHostFactory />
        </telerik:RadScheduleView.SchedulerDialogHostFactory>
        <telerik:RadScheduleView.ViewDefinitions>
            <telerik:DayViewDefinition/>
            <telerik:WeekViewDefinition/>
            <telerik:MonthViewDefinition/>
            <telerik:TimelineViewDefinition/>
        </telerik:RadScheduleView.ViewDefinitions>
    </telerik:RadScheduleView>
</Grid>

And here's my property. Despite the two-way binding it is always null:

Salesmen.xaml.cs:

string totalSalesmen { get; set; }

I've heard about the VisualTreeHelper and the LogicalTreeHelper. These might enable another approach - finding the control and getting and them manually. However, VisualTreeHelper only sees the LayoutRoot and it's children (not UserControl.Resources), and LogicalTreeHelper does not seem to be available (it's a SilverLight 5 project; I don't know what framework is used by Silverlight 5. I understand that LogicalTreeHelper is only available in 4.5 and later)

Thank you for you assistance. Note: this question will get a +50 bounty. The system requires me to wait for 2 days to put a bounty, so I will put the bounty and accept the answer after 2 days. I will let you know if your answer works before that.

like image 579
Zesty Avatar asked May 11 '15 08:05

Zesty


People also ask

What does bind this mean?

The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.

What does bind () do in C?

The bind() function binds a unique local name to the socket with descriptor socket. After calling socket(), a descriptor does not have a name associated with it. However, it does belong to a particular address family as specified when socket() is called. The exact format of a name depends on the address family.

Why do we use the bind method?

We use the Bind() method to call a function with the this value, this keyword refers to the same object which is currently selected . In other words, bind() method allows us to easily set which object will be bound by the this keyword when a function or method is invoked.

What does .bind do in JS?

bind is a method on the prototype of all functions in JavaScript. It allows you to create a new function from an existing function, change the new function's this context, and provide any arguments you want the new function to be called with.


2 Answers

Your Binding to totalSalesmen and everything inside the EditAppointmentTemplate1 will not have any effect as long as the Template is never instantiated. Think of a Template (both ControlTemplate and DataTemplate) as a blueprint. The elements that are defined inside are only instantiated when the template is used somewhere.

Do you have a usage somewhere? like this:

<Grid>
    ...
    <SchedulerDialog Template="{StaticResource EditAppointmentTemplate1}"/>
    ...
</Grid>

[Edit #1]

Ok let's see... your twoway Binding to totalSalesmen looks ok, albeit a bit smelly. I think the property totalSalesmen should rather live in the DataContext (and it would be easier to bind against). But first let's try to make your code work, maybe we make it nice later:

The Problem

When (in one single xaml file) using ElementName in Bindings while at the same time using templates to define parts of the UI (and remember: the stuff in templates is only created when it is used somewhere, and the creation may happen at a different point in time) there is the risk, that elements that you expect to know each other are in fact created in diffent NameScopes. And your affected ElementName-Bindings won't work. Just silently won't work.

A Cure

You can try a trick: Ensure that you have a StaticResource that holds the reference to the element you originally wanted to use by ElementName. And then you just write a Binding against that StaticResource. See what I've done here:

<UserControl x:Class="Salesmen" ... x:Name="me">
  <UserControl.Resources>
    <BindableObjectReference x:Key="MyUserControl" Object="{Binding ElementName=me}"/>
    <ControlTemplate x:Key="EditAppointmentTemplate1"
        TargetType="local:SchedulerDialog">
        ...
        <TextBox Text="{Binding Path=Object.totalSalesmen,
            Source={StaticResource MyUserControl}, Mode=TwoWay}"/>
        ...
    </ControlTemplate>
  </UserControl.Resources>

and the code

public class BindableObjectReference : DependencyObject
{
    public object Object
    {
        get { return GetValue( ObjectProperty ); }
        set { SetValue( ObjectProperty, value ); }
    }

    public static readonly DependencyProperty ObjectProperty =
        DependencyProperty.Register( "Object", typeof( object ),
        typeof( BindableObjectReference ), new PropertyMetadata( null ) );
}

[Edit #2]

When you bind to a property of the DataContext, you just specify the path but not the source (implicitly the source will be the DataContext):

Text="{Binding Path=totalSalesmen, Mode=TwoWay}"
like image 109
Martin Avatar answered Oct 19 '22 03:10

Martin


If you Add TotalSalesmen to the DataContext of the template, e.g.

public class SpecialAppointment: Appointment
{
  private int _totalSalesmen = 0;
  public int TotalSalesmen 
  {get {return _totalSalesmen; }
  {set {_totalSalesmen = value; OnPropertyChanged(()=> this.TotalSalesmen);}
}

You should be able to bind the text box thus:

<TextBox Text="{Binding TotalSalesmen, Mode=TwoWay}" />

Note the binding is case-sensitive, and it must match the property name TotalSalesmen and not the field _totalSalesmen.

like image 38
Chui Tey Avatar answered Oct 19 '22 05:10

Chui Tey