WPF UserControl property binding for some and not others - wpf

I have a the following three items in my xaml that have there visibility changed depending on a boolean property located in the DataContext of the page.
<worklist:PhysicianQuickInsert Visibility="{Binding IsInsertingPhysician, Converter={StaticResource NullEmptyFalseToInvisibileConverter}}" />
<shared:LoadingIndicator Visibility="{Binding IsInsertingPhysician, Converter={StaticResource NullEmptyFalseToInvisibileConverter}}" />
<TextBlock Text="Test" Foreground="Red" Visibility="{Binding IsInsertingPhysician, Converter={StaticResource NullEmptyFalseToInvisibileConverter}}" />
The TextBlock and LoadingIndicator are becoming visible/collapsed, but the PhysicianQuickInsert fails to do anything.
I have verified that the getter of the boolean property is never retrieved for the PhysicianQuickInsert.
Why would this happen? PhysicianQuickInsert is a usercontrol, as is the LoadingingIndicator.

This can happen if you defined a new Visibility property on your UserControl. If you've done this, you may need to make sure that it's binding two-way by default, has a proper setter, etc.

Following the comments on my answer, this issue was that this user control binds to a another datacontext (different type) within it. I added a RelativeSource and it worked.
Thanks everyone!

Related

Create control conditionally - bindings

<Page>
<local:AControl Visibility="{Binding ElementName=SendPushWindow,Path=DataContext.SelectedItem,Converter={StaticResource ToVisibilityConverter},ConverterParameter=A}"/>
<local:BControl Visibility="{Binding ElementName=SendPushWindow,Path=DataContext.SelectedItem,Converter={StaticResource ToVisibilityConverter},ConverterParameter=B}"/>
<local:CControl Visibility="{Binding ElementName=SendPushWindow,Path=DataContext.SelectedItem,Converter={StaticResource ToVisibilityConverter},ConverterParameter=C}"/>
<local:DControl Visibility="{Binding ElementName=SendPushWindow,Path=DataContext.SelectedItem,Converter={StaticResource ToVisibilityConverter},ConverterParameter=D}"/>
<local:EControl Visibility="{Binding ElementName=SendPushWindow,Path=DataContext.SelectedItem,Converter={StaticResource ToVisibilityConverter},ConverterParameter=E}"/>
</Page>
And in parent page public InterfaceType SelectedItem { get; set; }
Hello,
I have some controls which visibility depends on SelectedItem type, ToVisibilityConverter just change the visibility depending on ConverterParameter.
This example works, but of course if the item underlying in SelectedItem is changed, there are binding errors on the other controls which visibility is collapsed, that's obvious, because properties don't match. So my goal is to remove that binding errors - to do that I should do something that shouldn't create or update control if it is not of correct type. How to achieve it? How to handle these solutions? For example kind of injecting but how?
Ok I found an easy solution:
<ContentControl Content="{Binding ElementName=SendPushWindow,
Path=DataContext.SelectedItem,
Converter={StaticResource ToTemplateConverter}}">
And in converter just return that control :) Sorry for bothering

Bind a ComboBox to two DataContexts

I have a ComboBox in my wpf application.
It's ItemsSource is binded to some table in my DataSet.
I need the text property to be binded to another's object property . I doesn't work because the ComboBox doesn't want to get two DataContexts. How can I solve this problem?
<StackPanel Width="Auto" Height="Auto" MinWidth="296" Orientation="Vertical" x:Name="MyStackPanel">
<ComboBox x:Name="MyComboBox" ItemsSource="{Binding}" Text={Binding Path=MyProperty} />
</StackPanel>
In the code behind :
MyComboBox.DataContext = MyDataSet.Tables[MyTable];
MyStackPanel.DataContext = MyObject;
I want the ComboBox to show items from one DataContext but to show the text from another DataContext. How can I do it?
Don't use DataContext. Set the Source property of your bindings in XAML or create the bindings in code and set the Source property there.
Why are you assigning something to the datacontext of the stackpanel? From the looks of it, its not used.
Your code should work if MyDataSet.Tables[MyTable] returns an enumeration and contains a property called MyProperty.
What do you mean when you say that the combobox "doesn't want to get two DataContexts"?
Look into the properties IsEditable and IsReadOnly of the combobox.
Something like
<ComboBox x:Name="MyComboBox" ItemsSource="{Binding}" Text={Binding ElementName=MyStackPanel Path=DataContext.MyProperty} />

WPF: Collection dependency property "is read-only and cannot be set from markup"

I am creating a user control to display a three-month calendar. The control is based on the WPF Calendar control (WPF Toolkit 2009-06), and I want to pass several of the Calendar's properties through to corresponding properties of my user control. The user control properties are set up as Dependency Properties, and their underlying types match the types of the Calendar properties. Here is my markup:
<StackPanel>
<toolkit:Calendar Name="MasterCalendar"
SelectionMode="{Binding Path=SelectionMode, Mode=OneWay}"
SelectedDate="{Binding Path=SelectedDate, Mode=OneWayToSource}"
SelectedDates="{Binding Path=SelectedDates, Mode=OneWayToSource}"/>
<toolkit:Calendar Name="SlaveCalendar1"
DisplayDate="{Binding DisplayDate, Converter={StaticResource IncrementalMonthConverter}, ElementName=MasterCalendar, Mode=OneWay}"
SelectionMode="{Binding Path=SelectionMode, Mode=OneWay}"
SelectedDate="{Binding Path=SelectedDate, Mode=OneWayToSource}"
SelectedDates="{Binding Path=SelectedDates, Mode=OneWayToSource}"/>
<toolkit:Calendar Name="SlaveCalendar2"
DisplayDate="{Binding DisplayDate, Converter={StaticResource IncrementalMonthConverter}, ElementName=SlaveCalendar1, Mode=OneWay}"
SelectionMode="{Binding Path=SelectionMode, Mode=OneWay}"
SelectedDate="{Binding Path=SelectedDate, Mode=OneWayToSource}"
SelectedDates="{Binding Path=SelectedDates, Mode=OneWayToSource}"/>
</StackPanel>
All of the properties bind without problem, except for the SelectedDates property. I get the following error on its binding:
'SelectedDates' property is read-only and cannot be set from markup.
I suspect that it is because the SelectedDates property is a collection, but I am not sure how to fix the problem. Can anyone enlighten me on the cause of the problem and suggest a fix? Thanks for your help.
If I understand you well, you have Dependency properties in your code behind that match in name and type the properties of the Calendar Controls in your user control. You are trying to assign the SelectedDates Collection of the various Calendar Controls to the Dependency property of the same name in your code behind.
You can simply do this by a line of code:
this.SelectedDates=SlaveCalendar1.SelectedDates
In an appropriate EventHandler that fires when a selected date is added.
Even though you set the binding to OneWayToSource the SelectedDates= piece of code is an assignment. As the SelectedDates Property has no setter, it is not possible to write this piece of code.
Here you can find a link to the Calendar Control's documentation

How do I databind to the control's property rather than the datacontext?

I have a sub control embedded inside my main control, it allows the user to edit an address. Because this is reused all over the place (sometimes in multiple places on one control) I bind it like so
<Controls:EditAddressUserControl DataContext="{Binding Path=HomeAddress}"/>
<Controls:EditAddressUserControl DataContext="{Binding Path=WorkAddress}"/>
But the EditAddressUserControl needs access to the main control's list of CountrySummary objects so it can choose which country the address belongs to.
I have added a Countries DependencyProperty to EditAddressUserControl and added
Countries="{Binding Countries}"
So far all is going well, the EditAddressUserControl.Countries property has the correct countries in it. However, how do I databind my Combobox.ItemsSource to that in XAML?
I still want everything on my EditAddressUserControl to bind to its DataContext, but the ComboBoxCountries.ItemsSource needs to bind to "this.Countries".
How do I do that?
I've tried this
<ComboBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Controls:EditAddressUserControl}}, Path=Countries}" />
I saw no binding errors in the output box, but I also saw no items in the combobox.
You can accomplish this by using a RelativeSource for the binding source, instead of the DataContext.
This would most likely look something like:
<ComboBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Controls:EditAddressUserControl}}, Path=Countries}" />
The way to do it was to stop using DataContext completely. Instead I added a DependencyProperty to my control
public static DependencyProperty AddressProperty = DependencyProperty.Register("Address", typeof(EditPostalAddressDto), typeof(EditPostalAddressControl));
Then in the parent control instead of setting DataContext="..." I set Address="..." - The XAML for the control is then changed to include an ElementName on the binding
<UserControl ..... x:Name="MainControl">
<TextBox Text="{Binding ElementName=MainControl,Path=Address.Region}"/>
Now I can specifically bind to the Address property, but also bind to properties on the main data context.

Binding property to Silverlight dependency property independent of DataContext

I'm trying to make an Address control that has an IsReadOnly property, which will make every TextBox inside read only when set to true.
<my:AddressControl Grid.Column="1" Margin="5" IsReadOnly="True"/>
I've managed to do this just fine with a dependency property and it works.
Here's a simple class with the dependency property declared :
public partial class AddressControl : UserControl
{
public AddressControl()
{
InitializeComponent();
this.DataContext = this;
}
public static readonly DependencyProperty IsReadOnlyProperty =
DependencyProperty.Register("IsReadOnly", typeof(bool),
typeof(AddressControl), null);
public bool IsReadOnly
{
get { return (bool)GetValue(IsReadOnlyProperty); }
set { SetValue(IsReadOnlyProperty, value); }
}
}
In the XAML for this codebehind file I have a Textbox for each address line:
<TextBox IsReadOnly="{Binding IsReadOnly}" Text="{Binding City, Mode=TwoWay}"/>
<TextBox IsReadOnly="{Binding IsReadOnly}" Text="{Binding State, Mode=TwoWay}"/>
<TextBox IsReadOnly="{Binding IsReadOnly}" Text="{Binding Zip, Mode=TwoWay}"/>
Like i said this works just fine.
The problem is that the Address control itself is bound to its parent object (I have several addresses I am binding).
<my:AddressControl DataContext="{Binding ShippingAddress, Mode=TwoWay}" IsReadOnly="True">
<my:AddressControl DataContext="{Binding BillingAddress, Mode=TwoWay}" IsReadOnly="True">
The problem is that as soon as I set DataContext to something other than 'this' then the binding for IsReadOnly breaks. Not surprising because its looking for IsReadOnly on the Address data entity and it doesn't exist or belong there.
I've tried just about every combination of binding attributes to get IsReadOnly to bind to the AddressControl obejct but can't get it working.
I've tried things like this, but I can't get IsReadOnly to bind independently to the AddressControl property instead of its DataContext.
<TextBox IsReadOnly="{Binding RelativeSource={RelativeSource Self}, Path=IsReadOnlyProperty}" Text="{Binding City, Mode=TwoWay}" />
I think I'm pretty close. What am I doing wrong?
With this answer (actually my own answer to a similar question) I have a good [better] solution.
I still have to iterate through the textboxes, but I don't have to set the actual value. I can create bindings in the codebehind - just not with XAML.
I think you're stuck, at least, if you want to do this just via binding. My guess is that you're going to have to resort to code-behind, presumably by iterating through your child textbox controls and setting their IsReadOnly propert as a side-effect of your Address control's IsReadOnly property.
Unlike some folks who think that any code sitting in a code-behind file is effectively an admission of failure, I don't get religious about it: if throwing some code into a code-behind is the easiest way to do something, that's where I put my code. On the contrary, if I have to spend half a day trying to figure out how to do something via binding that I could do in five minutes with a code-behind, that's failure, IMO.

Resources