x:Bind outside data templates is extremely inconsistent
Describe the bug
Apparently it is possible to use x:Bind to bind to a field in code behind outside a data template. Basically, escaping from the data template in use. Not entirely sure whether this is by design or just a lucky quirk of the XAML compiler and codegen (especially since this is not mentioned anywhere in the docs), but it works.
As a code example:
<UserControl
x:Class="MyNamespace.Views.MyUserControl"
xmlns:viewModels="using:MyNamespace.ViewModels"
models="using:MyNamespace.Models">
<UserControl.DataContext>
<viewModels:MyViewModel x:Name="ViewModel"/>
</UserControl.DataContext>
<UserControl.Resources>
<DataTemplate
x:Name="SomeDataTemplate"
x:DataTye="models:SomeModelTyppe">
<!--This works-->
<TextBlock Text="{x:Bind ViewModel.SomeText}"/>
</DataTemplate>
</UserControl.Resources>
<ListView
ItemsSource="{x:Bind ViewModel.MyItems}"
ItemTemplate="{StaticResource SomeDataTemplate}"/>
</UserControl>
You can see how the binding is escaping the data template and just targeting a field in code behind. The problem with this is that it's extremely fragile and inconsistent:
x:Bindto a property outside the data template works fine ✅x:Bindto that same property but with function binding fails to build ❌x:Bindto that same property from a visual state setter crashes at runtime ❌x:Bindto that same property with a converter crashes at runtime ❌
Steps to reproduce the bug
Steps to reproduce the behavior:
- Download this repro
- Open the solution, run the app
Expected behavior
🤷♂️ 🤷♂️ 🤷♂️
Actual behavior
The binding to the outside field (the view model) works just fine
Screenshots

| Windows 10 version | Saw the problem? |
|---|---|
| Insider Build (xxxxx) | |
| November 2019 Update (18363) | Yes |
| May 2019 Update (18362) | Yes |
| October 2018 Update (17763) | |
| April 2018 Update (17134) | |
| Fall Creators Update (16299) | |
| Creators Update (15063) |
| Device form factor | Saw the problem? |
|---|---|
| Desktop | Yes |
| Mobile | |
| Xbox | |
| Surface Hub | |
| IoT |
cc. @MikeHillberg
@fabiant3 For FYI
This almost looks like it shouldn't work at all. The DataTemplate has a defined DataType which it uses for its bindings.
I know with old-style Binding, this was possible with ElementName but I think there's an argument for having this functionality work correctly with x:Bind.
{Binding} and ElementName will walk up the element tree at runtime. IIRC x:Bind will statically search up the naming scopes -- the DataTemplate then the x:Class.
@jamesc I actually believe this was in fact supported, in particular because VS even has dedicated warnings for this. Like, if your x:DataType model has a property with the same name as the one from code behind, and you x:Bind to it, VS will say something like:
Warning, binding to property will cause the binding to reference the one from the outer scope.
As in, it looks like the system is perfectly aware of the possibility of binding outside of a data template, as @MikeHillberg said. I'd also argue this feature is extremely useful in many cases.
@MikeHillberg is it safe to say then that the issue is just that using anything other than standard x:Bind in this case (eg. function binding, binding from markup extension, etc.) breaks down? But like, that in theory this is a supported scenario that should work? 🤔
Yes, it should work. I expect some of the code for the (1903) feature went into a not-common code path, so missed the function binding case.
Thanks Mike for digging into this - yes, x:Bind'ing to named elements outside of the scope is an intentional feature. This is meant to be similar to the ElementName feature in {Binding}, allowing for binding to named elements outside of the current namescope. But unlike {Binding} which walks the visual tree at runtime to perform the name lookup, x:Bind walks the "markup tree" at compile time so it can perform compile time validation. You could see behavior differences when those don't align, like when using a Binding/x:Bind in a template from a ResourceDictionary. The Binding walks the visual tree from where the template is used, whereas x:Bind walks the markup tree from where the template is defined.
is it safe to say then that the issue is just that using anything other than standard
x:Bindin this case (eg. function binding, binding from markup extension, etc.) breaks down? But like, that in theory this is a supported scenario that should work? 🤔
Correct, these should work
I believe this is still an issue; is there any indication on when we can use x:Bind for this rather than Binding?
Imagine I have a UserControl containing a dependency property IsEditing (bool), I want to be able to set the visibility of a TextBlock vs a TextBox inside my DataTemplates.
With x:Bind that seems not possible because it only allows selecting items from the configured x:DataType, and not from the codebehind of the UserControl
Pseudocode, only to explain the use case of wanting to access data outside the DataType scope using x:Bind:
<UserControl Class="local:CarsList">
<UserControl.Resources>
<converters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
<DataTemplate x:Key="listItemTemplate" x:DataType:"models.Car">
<Grid>
<TextBlock Text="{x:Bind Brand}"
Visibility="{x:Bind IsEditing, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=True, Mode=OneWay}" />
<TextBox Text="{x:Bind Brand}"
Visibility="{x:Bind IsEditing, Converter={StaticResource BoolToVisibilityConverter}, Mode=OneWay}" />
</Grid>
</DataTemplate x:Key="listItemTemplate">
</UserControl.Resources>
</UserControl>
Doing the above will result in The property 'IsEditing' was not found in type 'Car'.
Workaround is giving the usercontrol an x:Name and fall back to Binding. Quite annoying 😕.
<UserControl Class="local:CarsList" x:Name="workaroundNameForControl">
<UserControl.Resources>
<converters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
<DataTemplate x:Key="listItemTemplate" x:DataType:"models.Car">
<Grid>
<TextBlock Text="{x:Bind Brand}"
Visibility="{Binding Path=IsEditing, ElementName=workaroundNameForControl, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=True, Mode=OneWay}" />
<TextBox Text="{x:Bind Brand}"
Visibility="{Binding Path=IsEditing, ElementName=workaroundNameForControl, Converter={StaticResource BoolToVisibilityConverter}, Mode=OneWay}" />
</Grid>
</DataTemplate x:Key="listItemTemplate">
</UserControl.Resources>
</UserControl>
Other workarounds for this case would be using a DataTemplateSelector but that won't work for all cases.
Unfortunately, I don't believe we can investigate this before the official WinUI 3 release in 2021. For your scenario in particular, you could try adding an x:Name to your root UserControl, then x:Bind using the named element (e.g. x:Bind RootUserControl.IsEditing). When looking outside of the namescope it was used in, x:Bind only looks for named elements, and not properties on the root data context.
Thanks for thinking along!
Actually I tried that (x:Bind workaroundNameForControl.IsEditing), but then I get the error The property 'IsEditing' was not found in type 'Car'..
I'm using VS 16.8 Preview 3.2 with an UWP project.
@hansmbakker does using {x:Bind ElementName=workaroundNameForControl, Path=IsEditing} work?
@stevenbrix Considering that x:Bind has no ElementName, no, it does not... :-) And even if it did, it would only work for plain property binding, not functions where the property would need to be passed as an argument, for instance.
I'm also struggling with this, and this is very important. Now that we have functions in x:Bind and prefer to avoid converters, reaching out to two places: data from the context of the data template and functions from the underlying control (data conversions, checks for visibility, disabled state, etc), this became very important. And Binding isn't even an alternative any more, not because it's quirkier and slower but because it doesn't do functions.
Conversion and other functions can be specified static and called as such (not nice but definitely a workaround) but properties of the control can't. Naming the control doesn't work, either, just as Hans pointed out above. And while the OP's solution might be OK for MVVMWHATEVERTHECURRENTBUZZWORDIS, it doesn't work for a plain user control: if we refer to the control itself this way, there will be complaints about IType_BindingsScopeConnector. Basically, with this trick, you can reach out to two data elements (template data context and control data context) but not the control itself as the second.
any update?
Hey all, we're still heads-down on major feature work/bug fixes for WinUI and Project Reunion, so there likely won't be any movement on this for several months. Thanks!
{Binding} and ElementName will walk up the element tree at runtime. IIRC x:Bind will statically search up the naming scopes -- the DataTemplate then the x:Class.
@MikeHillberg @Sergio0694 what if in nested DataTemplate:

@Sergio0694 not work either.

error CS1503: Argument 1: cannot convert from 'System.WeakReference' to 'Windows.UI.Xaml.Controls.Page'
Unfortunately, I don't believe we can investigate this before the official WinUI 3 release in 2021. For your scenario in particular, you could try adding an
x:Nameto your rootUserControl, then x:Bind using the named element (e.g.x:Bind RootUserControl.IsEditing). When looking outside of the namescope it was used in, x:Bind only looks for named elements, and not properties on the root data context.
not work, see above.
after change the generated code, it compiles. @RealTommyKlein


Seems related to #2237 as well?
My latest trick is to do something like this:
<Page x:Name="ThisPage"...>
<ItemsControl>
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="local:MyType">
<Button Command="{Binding ViewModel.SaveCommand, ElementName=ThisPage}" CommandParameter="{x:Bind (local:MyType)}"/>
But x:Bind should just let us break into the different scopes we need:
- Local (data item itself)
- Container (ListViewItem for instance)
- "Parent" (ListView for instance)
- "Global" (i.e. Page)
I think that'd cover the majority of scenarios I ever need when dealing with templating. The compiler should just be able to walk the scope up if it's not finding the reference path at each tier.
@michael-hawker your latest trick doesn't work for ItemsRepeater, although it does for ListView/ItemsControl. That is mind blowing! I really want to have at least some workaround, but I can't, unless I switch from ItemsRepeater to ListView/ItemsControl and only then can switch to use Binding? Crazy! Something is wrong here even with Binding. Please look into it!
For me it actually worked only by giving a name to my UserControl (which is used in a ListView), and then replacing x:Bind with Binding. They should really fix this.
This works:
<controls:CustomControl Visibility="{Binding ElementName=ControlName, Path=Object.IsReady, Mode=OneWay}"></controls:CustomControl>
This works but it fails eventually to evaluate IsReady when it's true and the control remains hidden only for certain items in the list.
<controls:CustomControl Visibility="{x:Bind Object.IsReady, Mode=OneWay}"></controls:CustomControl>
This also comes up for ItemsPanelTemplates, x:Bind isn't usable in those, which is frustrating. Sometimes you want to configure your layout panel change for ItemsControl based on other properties.
Instead trying to bind to a page property gets you: XamlCompiler error WMC1111: DataTemplates containing x:Bind need a DataType to be specified using 'x:DataType', which isn't a thing for ItemsPanelTemplate (if you try you get XamlCompiler error WMC0908: DataType is only allowed for DataTemplate.)
Related SO post as well: https://stackoverflow.com/questions/11307531/binding-inside-the-itemspaneltemplate-from-parent-in-windows-phone
Also found myself needing this the other day in the Store. I just couldn't for the love of me get this to work, as the XAML compiler would just refuse to compile code with a binding to something outside of a template, even if visible in XAML. Had to come up with some proxy object to bind to to, as I just couldn't get a normal binding to the control's property directly to work.
A fix for this would really, really be welcome 😄
Also found myself needing this the other day in the Store. I just couldn't for the love of me get this to work, as the XAML compiler would just refuse to compile code with a binding to something outside of a template, even if visible in XAML. Had to come up with some proxy object to bind to to, as I just couldn't get a normal binding to the control's property directly to work.
A fix for this would really, really be welcome 😄
@Sergio0694 Find Ancestor extension in the Toolkit? https://docs.microsoft.com/windows/communitytoolkit/extensions/frameworkelementextensions#ancestortype
I mean, yes, but I wanted a statically-typed and reflection-free solution, that's why x:Bind is cool 😅
Not sure whether this is a regression and if so, when it was introduced, but now I can't even get the only scenario that was working back when I first opened this issue to work at all anymore. Even just binding to the top viewmodel in a page fails to build. This is a pretty big issue because it blocks many scenarios where you need a backlink to a parent viewmodel for shared functionality (eg. for commands), and the only solution is to either use a static resource (which is only applicable in very few and specific cases), or having to add extra wrapping models just for that, which adds overhead. This is affecting other internal partners as well, and has been broken for years, with no ETA for a fix at all either. I'm pretty sure it's also broken on WinUI 3 too 😥
Not sure whether this is a regression and if so, when it was introduced, but now I can't even get the only scenario that was working back when I first opened this issue to work at all anymore. Even just binding to the top viewmodel in a page fails to build. This is a pretty big issue because it blocks many scenarios where you need a backlink to a parent viewmodel for shared functionality (eg. for commands), and the only solution is to either use a static resource (which is only applicable in very few and specific cases), or having to add extra wrapping models just for that, which adds overhead. This is affecting other internal partners as well, and has been broken for years, with no ETA for a fix at all either. I'm pretty sure it's also broken on WinUI 3 too 😥
noone cares
@michael-hawker your latest trick doesn't work for ItemsRepeater, although it does for ListView/ItemsControl. That is mind blowing! I really want to have at least some workaround, but I can't, unless I switch from ItemsRepeater to ListView/ItemsControl and only then can switch to use Binding? Crazy! Something is wrong here even with Binding. Please look into it!
There is one workaround. You have to create a kinda display class. Just for the purpose of the example.
Code behind
[INotifyPropertyChanged]
public partial class FooViewModel {
[ObserveableProperty] private List<FixedFooItem> _fooItems = new();
private void Whenever() {
List<FooItem> items = ...;
for(FooItem item in items) {
_fooItems.Add(item, DoSomething)
}
}
[RelayCommand]
private void DoSomething(FooItem item) {
//..
}
}
[INotifyPropertyChanged]
public partial class FooItem {
[ObserveableProperty] private string _name { get; set; }
}
[INotifyPropertyChanged]
public partial class FixedFooItem {
[ObserveableProperty] private FooItem _data;
public IRelayCommand DoSomethingCommand { get;set; }
public FixedFooItem(FooItem item, IRelayCommand doSomethingCommand)
{
_data = item;
DoSomethingCommand = doSomethingCommand;
}
}
View
<ScrollViewer IsVerticalScrollChainingEnabled="True">
<ItemsRepeater ItemsSource="{x:Bind ViewModel.FooItems, Mode=OneWay}">
<ItemsRepeater.Layout>
<UniformGridLayout MinItemWidth="100" MinItemHeight="100" MinRowSpacing="12" MinColumnSpacing="12"/>
</ItemsRepeater.Layout>
<ItemsRepeater.ItemTemplate>
<DataTemplate x:DataType="local:FixedFooItems">
<Button Content="{x:Bind Data.Name}" Command="{x:Bind DoSomethingCommand}" CommandParameter="{x:Bind Data}"/>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</ScrollViewer>
I hope there is coming a fix anytime soon.
Unrelated, but want to call this out: @LeonSpors I'd strongly recommended not to use [INotifyPropertyChanged] and instead to inherit from ObservableObject if you can. I implemented the attribute to help in scenarios where you could not inherit from ObservableObject, eg. if you had to inherit from another type which didn't have the interface, so you could still get the functionality from it. But if you can, do prefer inheriting from ObservableObject instead, as it'll reduce code duplication and binary size, as every viwmodel will just share the same implementation of all the helper methods from the base class instead of each carrying its own private copy for no reason 🙂
Any updates so far?