Binding Visibility to DataContext - xaml

I have a value converter that converts null to Visibility.Collapsed. Now I try to use it in a user control so that the whole control would collapse when it's DateContext is null
The control looks like this:
<UserControl x:Class="PhoneApp.Controls.Header"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Visibility="{Binding Converter={StaticResource ToVisibility}}"
d:DesignHeight="150" d:DesignWidth="480"> <-- some body here -->
And it is used like this
<my:Header DataContext="{Binding SectionHeader}"/>
Where SectionHeader is a view model property.
I hava a similar control where I don't bind DataContext but some custom DP and the collapsing there works fine. However, in this one, the value converter seems to be called only when the SectionHeader != null. When it is null, the control is rendered with empty children.
I thought about not using DataContext here but the control is much cleaner with it.
Why binding to DataContext doesn't work? What do you suggest?

In this case, when DataContext is null, binding will use value specified in TargetNullValue property. So simply set TargetNullValue=Collapsed and you're good to go :
Visibility="{Binding TargetNullValue=Collapsed}"
Reference : [How to Set TargetNullValue to Visibility.Collapsed in Binding]

Related

XAML binding intellisense in a separate ContentView file used in a ListView

I have a ListView with this item template:
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<views:ProjectListEntry />
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
ProjectListEntry is fairly complex and is used in another ListView, so I have it in its own file. I've set it up like this:
<ContentView
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
...
BindingContext="{x:Static vms:DesignTimeData.ProjectListEntryVm}">
As you can see, to get binding Intellisense (using ReSharper), I tried to set BindingContext to a static member on the DesignTimeData class. This works fine for my Pages (where I replace the BindingContext at runtime), but for ContentViews used in ListViews, the ContentView's BindingContext seems to be inherited (from the ViewCell, I guess). This means that the explicit BindingContext on my ContentView will actually override the BindingContext set on the ViewCell by the ListView, and all my list elements will reflect the static design-time data at runtime. But if I remove the BindingContext, I get no intellisense for the members I bind to inside the ContentView file.
Is there a simple way to get Intellisense for bindings in a ContentView like this?
(As mentioned, I can't inline the ContentView in the ListView definition, because the ContentView is fairly complex and used in several lists. I also can't use some kind of VM locator, because although I'm using bindings, I'm not using "full" MVVM - I'm using a Redux-like architecture instead. And I guess a VM locator wouldn't work for this case anyway for the same reasons the above doesn't work.)
(Cross-posted from the Xamarin Forums where I didn't get any reply.)
This solution seems to work fine. In short: Add
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
and use d:DataContext instead of BindingContext. Going from the example above, it should look like this:
<ContentView
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
...
BindingContext="{x:Static vms:DesignTimeData.ProjectListEntryVm}">
This leads to working binding intellisense from ReSharper and does not cause issues when run.

How to position relative to a child element within another control in XAML

In a UWP app, I have a custom UserControl with some child controls (text boxes, labels, etc.). I have a Page that includes that UserControl as a child element. Now, I want to place a button below that UserControl and align it with one of the control's child text boxes using a RelativePanel. I can't figure out a way to access the child element.
For example, I have a custom control:
<UserControl
x:Class="Sandbox.FooControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Sandbox"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<Grid>
<TextBox
x:Name="TheTextBoxIWantToAlignWith"
x:FieldModifier="public"/>
</Grid>
And now I want to align with "TheTextBoxIWantToAlignWith":
<UserControl
x:Class="Sandbox.FooParentControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Sandbox"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<RelativePanel>
<local:FooControl
x:Name="Foo"
RelativePanel.AlignTopWithPanel="True"
RelativePanel.AlignHorizontalCenterWithPanel="True"/>
<Button
RelativePanel.Below="Foo"
RelativePanel.AlignLeftWith="Foo.TheTextBoxIWantToAlignWith"/> <!-- This doesn't work -->
</RelativePanel>
Obviously this doesn't work ("RelativePanel error: The name 'Foo.TheTextBoxIWantToAlignWith' does not exist in the current context."). I tried:
Setting the FieldModifier to public on the child TextBox
Exposing the TextBox as a public property in code-behind
Exposing the TextBox as a DependencyProperty in code-behind
I really want to avoid flattening out the UserControl into the parent page because it can be reused elsewhere. Is there any way to do this?
I ended up working around the issue with code-behind, similar to Lindsay's suggestion. I hooked into the LayoutUpdated event, which calculated and set the margin. Something like this:
private void AlignButton()
{
var transform = Foo.TheTextBoxIWantToAlignWith.TransformToVisual(RootPanel);
var textBoxRightEdge = transform .TransformPoint(new Point()).X + Foo.TheTextBoxIWantToAlignWith.ActualWidth;
var rightMargin = RootPanel.ActualWidth - textBoxRightEdge;
if (Math.Abs(TheButtonIWantToAlign.Margin.Right - rightMargin) >= 1)
TheButtonIWantToAlign.Margin = new Thickness(0, 0, rightMargin, 0);
}

Implement IE/Microsoft Edge bottom bar in XAML

I am a huge fan of the browser on Windows phone and I want to port a similar bottom bar to my app. Right now, I am using a standard CommandBar.
<Page.BottomAppBar>
<CommandBar>
<AppBarButton Icon="Go" Click="Go"/>
<CommandBar.SecondaryCommands>
<AppBarButton Icon="Setting" Label="Settings" Click="ShowSettings"/>
</CommandBar.SecondaryCommands>
</CommandBar>
</Page.BottomAppBar>
As this wastes screen space, I really want to make use of the remaining space of the bar to add something like app status (in place of the address bar of Edge/IE), something like download/upload progress. Unfortunately, the CommandBar does not allow introducing things like TextBlock or ProgressRing. To make use of those controls, we need to change to an AppBar instead. But then, I cannot use the features of CommandBar like the adding 3 dots buttons to open up the hidden buttons.
Is there an easy way to achieve this i.e. combining the flexibility of AppBar and the 3-dot feature of CommandBar?
CommandBar only accept the control that inherit ICommandBarElement interface.
We can create one UserControl which inherit ICommandBarElement, simply did a small test without optimize the code, take a look to see if it helps:
public sealed partial class MyUserControl1 : UserControl, ICommandBarElement
{
public MyUserControl1()
{
this.InitializeComponent();
}
private bool _IsCompact = true;
bool ICommandBarElement.IsCompact
{
get
{
return _IsCompact;
}
set
{
_IsCompact = value;
}
}
}
Also the UserControl XAML:
<UserControl
x:Class="App10.MyUserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App10"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignWidth="400" Height="38.027">
<Grid>
<TextBlock Foreground="DarkBlue">asdsadasdasdasdasda</TextBlock>
</Grid>
And then we use the userControl in the CommandBar, here we go:
http://i.stack.imgur.com/Bgug9.png
Note: please further optimize it for instance register some Text dependency properties to enable accept the data binding.
Per the documentation on MSDN you can use the CommandBar.Content property which corresponds to the empty area to the side of any primary commands. To alter the alignment of the content you'd need to change the CommandBar.HorizontalContentAlignment property.
<CommandBar HorizontalContentAlignment="Stretch">
<AppBarButton Icon="Go" Click="Go"/>
<CommandBar.SecondaryCommands>
<AppBarButton Icon="Setting" Label="Settings" Click="ShowSettings"/>
</CommandBar.SecondaryCommands>
<CommandBar.Content>
<Grid>
<TextBox HorizontalAlignment="Stretch"
VerticalAlignment="Top"
Margin="12,8"/>
</Grid>
</CommandBar.Content>
</CommandBar>
And as of Win10 the recommendation is to place the CommandBar inline instead of using the Page.TopAppBar or Page.BottomAppBar properties. The one scenario in which you may still want to use the Page.BottomAppBar property is to ensure the CommandBar remains visible when the software keyboard appears.

ElementName binding doesn't resolve properties

When I bind something to the SelectedItem of a ListView using ElementName, the properties cannot be resolved.
I can still build and run my app, but because of this error I'm not sure that I didn't make any typo's.
I read and tried the answer given in ElementName Binding is failing but Source={x:Reference ...} doesn't seem to exist in the WinRT framework.
Just an example:
My page has a property MyContainerObject with an IEnumerable<MyParentObject> inside called MyParents. Each MyParentObject has an IEnumerable<MyChildObject> called MyChildren inside.
The DataContext of my page:
DataContext="{Binding RelativeSource={RelativeSource Self}}"
I have ListView with the following XAML properties:
x:Name = "FirstListView"
ItemsSource = {Binding MyContainerObject.MyParents}
Then I have another ListView with the following XAML properties:
x:Name = "SecondListView"
ItemsSource = "{Binding SelectedItem.MyChildren, ElementName=FirstListView}"
Now ReSharper gives me the following warning:
Cannot resolve property 'MyChildren' in data context of type 'object'.
Add this to your listview:
d:DataContext="{d:DesignInstance model:MyParentObject}"

Bind tab to observablecollection in model in xaml

I have a question concerning data binding with tabs.
I have the following xaml code:
<Window x:Class="SuperAtomsController.GUI.windowAnalog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="windowAnalog" Height="900" Width="1400"
DataContext="{Binding RelativeSource={RelativeSource self}}">
<Grid>
<TabControl Height="459" HorizontalAlignment="Left" Margin="188,278,0,0" Name="tabControl1" ItemsSource="{Binding Path=model.sequences}" VerticalAlignment="Top" Width="883">
</TabControl>
</Grid>
</Window>
And the code behind:
public partial class windowAnalog : Window
{
public Data model;
public windowAnalog(Data model)
{
this.model = model;
InitializeComponent();
}
}
But with this nothing appears in the tabcontrol (model.sequences is of the type ObservableCollection<>). If remove the itemssource in xaml and add the following in the c# code tabControl1.ItemsSource = model.sequences; after the InitializeComponent(); it works fine. What am I missing?
Clearly your binding isn't resolving, check your debug output window for helpful diagnostic messages.
I can't recall but I think model may need to be a property instead of a field for WPF property path to work. Otherwise maybe it was a problem with the DataContext. You coudl try doing this.DataContext = this to your constructor before InitializeComponent() instead of your DataContext xaml.