WPF Bind to element in parent window - c#

I'm trying to bind element's property in a child control to an element's property ina parent window, it doesn't work..
Here is png of what I'm trying to do:
Here is the xaml that doesn't work:
CurrentDate="{Binding ElementName=TimeBar, Path=SelectionStart,RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"
Thanks.

create a dependency property in your usercontrol and then bind to it in your window
something like that: DependencyProperty implementations you can find all around here on stackoverflow
<YourUsercontrol x:Name="uc">
<YourSomeControl CurrentDate="{Binding ElementName=uc, Path=MyDp}"/>
</YourUsercontrol>
xaml window
<Window>
<ElementInParent x:Name="eip" />
<YourUsercontrol MyDp="{Binding ElementName=eip, Path=PropertyFromElementInParent}"/>

based on the following Answer LINK the SelectionStart is not a Bindable Probperty by default so you need to create a attached behavior or something similar

Binding ElementName along with Relative Source is not correct approach.
Besides the UserControl does not know the ElementName of the Parent since the two are in different XAML.
One approach is to set the data context of user control with the element name you want to bind it to and then use normal binding Path.
As shown in the example below:
In main window, we have a textbox and a user control.
We are setting data context of the user control with the text box.
In the user control, we are binding the Text property of the DataContext (which is essentially TextBox of main window).
<Window
xmlns:self="clr-namespace:experiments"
>
<StackPanel>
<TextBox x:Name="Name" Width="100"/>
<self:UserControl1 DataContext="{Binding ElementName=Name}"/>
</StackPanel>
</Window>
<UserControl x:Class="experiments.UserControl1">
<Grid>
<TextBlock Text="{Binding Path=Text}" Width="100" Background="AliceBlue" Height="50"/>
</Grid>
</UserControl>

Related

Custom control binding is not updating

I'm having trouble getting my binding to work correctly. Basically I have this, call this Control1.xaml. The commented out portion of the code binds correctly and updates as expected.
<progControls:CalibrationSummary
</progControls:CalibrationSummary>
<!--<TextBlock Text="{Binding Path=NumberOfCalibrations, Mode=OneWay}"/>-->
However, if I put that commented code in a custom control called CalibrationsSummary.xaml, I cannot bind this to NumberOfCalibrations.
Here's what CalibrationsSummary looks like
<Grid>
<TextBlock Text="{Binding Path=NumberOfCalibrations, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"/>
</Grid>
Note that I do use RelativeSource to try to get the property associated with Control1.xaml, tried TemplateBinding also. What am I doing wrong?
CalibrationSummary has no TemplatedParent unless you have put it in a ControlTemplate.
If you don't explicitly set the DataContext of the property of CalibrationSummary somewhere, it will inherit the DataContext from its parent control (which I assume is Control1) and then you can bind any property of this control's DataContext as usual without specifying any source:
<Grid>
<TextBlock Text="{Binding Path=NumberOfCalibrations}"/>
</Grid>

Set an existing control template as Content Property in WPF Code Behind

I have a very simple XAML
Visibility="Collapsed" X1="1" Margin="-35 0 0 0" Y1="0.4">
<Label.Content>
<Slider Grid.Column="0"
Width="20"
Height="65"
IsDirectionReversed="True"
Maximum="0.1"
Minimum="-4"
Orientation="Vertical"
x:Name="Slider1"
Value="{Binding Source={x:Reference scaleFactorModifier},
Path=ZoomScaleFactor, Mode=TwoWay}" />
</Label.Content>
</Label>
</SciChart:CustomAnnotation.Content>
</SciChart:CustomAnnotation>
Now for some reason I need to set the CustomControl.Content property from code behind. Is there any possibility I move all the label control to some style and template and set the CustomControl content property at runtime with that particular style or template.
Update
Reason for using Code behind
Actually I have Annotations property in my control which could have any control in it as we required. Previously I had used hard coded annotations in my control and placed the controls manually. Now I want to bind the Annotations property. I could create a property of this type and add CustomAnnotation objects in it. But customAnnotation objects need to have labels and other controls in them, how could I do that?
If I have understood your problem correctly, I believe that you can do what you want by using a DataTemplate and a ContentControl. First, define a DataTemplate with your Label in:
<DataTemplate DataType="{x:Type YourPrefix:YourDataType}">
<!-- define your Label here -->
</DataTemplate>
Then you can set the Content property of your CustomControl to a ContentControl that has its own Content property set to an instance of an object of type YourDataType:
<ContentControl Content="{Binding InstanceOfYourDataType}" />
I'm aware that you want to do this programmatically, but that's easy enough to work out:
ContentControl contentControl = new ContentControl();
contentControl.Content = instanceOfYourDataType;
yourCustomControl.Content = contentControl;
I'm wondering if you even really need to use your CustomControl at all, but I'll leave that up to you.
I create a user control from that xaml and then set the CustomControl.Content as new instance of user control. This might not be the best solution, but this is all that I have for now.

Forcing a ListBox to re-render

Background:
I have a ListBox containing items defined by DataTemplates. Right now, if an object in the list has the property IsEditable set to true, the item's property information will be displayed inside of textboxes (via DataTemplate change), instead of textblocks (so the user can edit the content of that list item)
IsEditable is toggled on/off by a button inside of each list item. I have been told that we need to keep the state of all objects consistent, which means I can't just rebind the ItemsSource and lose everything.
Currently, I'm using this to re-render:
this.lbPoints.Dispatcher.Invoke(DispatcherPriority.Render, new Action(() => { }));
Question:
The aforementioned code snippet KIND OF does its job. By "kind of", I mean, it does eventually cause my data to become re-rendered, but only when I scroll to the bottom of the list and then scroll back up to the item i'm trying to re-render.
1) How can I re-render the data immediately without having to scroll around to get it to show up?
The guys commenting are right that you're going about this the wrong way... there is rarely a need to force a ListBox to re-render. You're probably causing yourself some additional grief trying to switch the DataTemplates (although it is possible). Instead of that, think about data binding the TextBox.IsReadOnly property to your IsEditable property:
<TextBox IsReadOnly="{Binding IsEditable}" Text="{Binding Text}" />
Another alternative is to use a BooleanToVisibilityConverter to show a different Grid in your DataTemplate when your IsEditable property is true. Unfortunately, that Converter doesn't have an inverse operation, so you could create an IsNotEditing property to bind to the Grid in the DataTemplate that is originally displayed. I'm not sure if that's clear... see this example:
<DataTemplate DataType="{x:Type YourPrefix:YourDataType}">
<Grid>
<Grid Visibility="{Binding IsNotEditing, Converter={StaticResource
BooleanToVisibilityConverter}}">
<!-- Define your uneditable UI here -->
</Grid>
<Grid Visibility="{Binding IsEditing, Converter={StaticResource
BooleanToVisibilityConverter}}">
<!-- Define your editable UI here -->
</Grid>
</Grid>
</DataTemplate>
You could also define your own BooleanToVisibilityConverter class that has an IsInverted property, so that you can just use the one IsEditing property. You'd need to declare two Converters still, like this:
<Converters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
<Converters:BoolToVisibilityConverter x:Key="InvertedBoolToVisibilityConverter"
IsInverted="True" />
Then your XAML would be like this:
<Grid Visibility="{Binding IsEditing, Converter={StaticResource
InvertedBoolToVisibilityConverter}}">
<!-- Define your uneditable UI here -->
</Grid>
<Grid Visibility="{Binding IsEditing, Converter={StaticResource
BoolToVisibilityConverter}}">
<!-- Define your editable UI here -->
</Grid>

Binding IsEnabled to the parent ViewModel instead of the UserControl ViewModel

I developed a user control in SilverLight that contains several child controls. Textboxes, ComboBoxes and so on.
The problem is, when I include that UserControl into a parent view and set the complete control to IsEnabled=False, the child controls in that specific UserControl are still enabled.
After all I found the problem.
Adding something like that, implies that the IsEnabled Binding is located in the UserControl binding, not as expected from myself in the DataContext of the parent.
<localControls:TeamEmployeeSelector Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"
IsEnabled="{Binding CanModify}" DataContext="{Binding Confidentiality}"/>
QUESTION:
But there's still the question how I can bind the IsEnabled to the ViewModel of the Parent? Because it's not very elegant to copy the CanModify Property to the ViewModel of the Child Control.
Instead of modifying a binding in some way (for example you can make it dependent on other control name as it is proposed in other answer) I would move separate the control which will be disabled and control where DataContext will be changed. For example:
<ContentControl IsEnabled="{Binding CanModify}" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2">
<localControls:TeamEmployeeSelector DataContext="{Binding Confidentiality}"/>
</ContentControl>
Here is how I would do this.
Your TeamEmployeeSelector UserControl will contain a single root level element which by default is a Grid and is given the name "LayoutRoot".
Now you can bind the IsEnabled property of all the child elements to the UserControl like this:-
<TextBox IsEnabled="{Binding Parent.IsEnabled, ElementName=LayoutRoot}" ... />
By using element-to-element binding you do not need to copy the CanModify property in to child view models.
Some might suggest that you simply add an x:Name to your UserControl element and then bind directly to it rather than going via the Parent property of the root element as I do above. That'll work ok in Silverlight 4 but not in 3 or WP7. Personally I prefer the above.
This is a scoping issue. Generally, when creating a UserControl, you want to set itself as the DataContext for its sub-elements. This is most easily accomplished in the constructor:
UserControlExample() {
InitializeComponent();
RootElement.DataContext = this;
}
Where RootElement is the name you give to this first child (usually a Grid or panel) of your UserControl.
From here you can set natural bindings for your sub-elements like so:
<TextBox x:Name="MainTextBox" IsEnabled={Binding IsEnabled} />
This works, since TextBox inherits the DataContext of the parent layout panel.
Finally, if you want to have your UserControl's IsEnabled property to be related to its parent, this is best done at the point of declaration:
<Grid>
<UserControlExample IsEnabled={Binding CanModify} />
</Grid>
This way you keep your concerns separate. The sub-controls don't care what the UserControl is reflecting. They just need to know how to enable/disable when the control's IsEnabled property flips.
sub-controls IsEnabled bound to --> (UserControlExample is DataContext)
UserControlExample.IsEnabled bound to --> (VM is DataContext)
VM.CanModify
I don't know if it's possible in Silverlight, but in WPF I would use RelativeSource.
Have a look here.
Hope this help !
<localControls:TeamEmployeeSelector Grid.Row="1" Grid.Column="0"
Grid.ColumnSpan="2" IsEnabled="{Binding ElementName=SomeElementName_With_Parent_ViewModel, Path=DataContext.CanModify}" DataContext="{Binding Confidentiality}"/>

How to bind property of one control to another?

I have a WPF control (ControlA) which references another control (ControlB) like so:
<Grid>
<controls:ControlB x:Name="ControlB" />
<my:DataGrid
x:Name="dataGridBackup"
ItemsSource="{Binding}"
AutoGenerateColumns="False" >
<my:DataGrid.Columns>
<my:DataGridCheckBoxColumn
Header="Connectable"
Binding="{Binding Connectable}" />
</my:DataGrid.Columns>
</my:DataGrid>
</Grid>
Now in ControlB I have a button and i want to bind the IsEnabled property to the Connectable column of my Grid on controlA.
I can get it working when i have the controls on the same page but not in the aboce scenario. I tried with
<Button
IsEnabled="{Binding ElementName=dataGridBackup, Path=SelectedItem.Connectable}">
</Button>
Button inside ControlB has no normal way to know what's outside the control ControlB. One possible solution is to add boolean dependency property to ControlB like IsConnectable. In XAML of control ControlA, bind the property to dataGridBackup with path, like you did. In XAML of control ControlB, bind the button's IsEnabled property to IsConnectable of ControlB.

Categories

Resources