In WinUI 3 Preview 1 Desktop - Binding markup extensions are not working correctly in some cases (see comments in XAML). Mode OneWay should be implicit, and all bellow mentioned bindings should work properly.
Steps to reproduce the bug
<StackPanel>
<!-- MyTextBox1 x:Bindng works. Text is updated from VM -->
<TextBox x:Name="MyTextBox1" Text="{x:Bind ViewModel.NewProductName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<!-- MyTextBox2 Binding does not work. Text is not updated from VM -->
<TextBox x:Name="MyTextBox2" Text="{Binding ViewModel.NewProductName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<!-- Command x:Bind works -->
<Button Command="{x:Bind ViewModel.AddNew}" Content="Add (works)" />
<!-- Command Binding does not work -->
<Button Command="{Binding ViewModel.AddNew, Mode=OneWay}" Content="Add (does not work)" />
<!-- Command Binding on nested property does not work -->
<Button Padding="5"
Command="{Binding ViewModel.ListViewModel.ClearFilter, Mode=OneWay}"
Content="Reset" />
<!-- Command x:Bind on nested property does not work without Mode -->
<Button Command="{x:Bind ViewModel.ListViewModel.ClearFilter}" Content="xBindWithoutMode" />
<!-- Command x:Bind on nested property works with explicit Mode OneWay. -->
<Button Command="{x:Bind ViewModel.ListViewModel.ClearFilter, Mode=OneWay}" Content="xBindWithOneWayMode" />
</StackPanel>
```C#
public sealed partial class ProductsView : UserControl
{
public ProductsView()
{
this.InitializeComponent();
var productsEntityChangesViewModel = App.Kernel.Get<ProductsEntityChangesViewModel>();
ViewModel = productsEntityChangesViewModel;
}
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel), typeof(ProductsEntityChangesViewModel), typeof(ProductsView), new PropertyMetadata(null));
public ProductsEntityChangesViewModel ViewModel
{
get { return GetValue(ViewModelProperty) as ProductsEntityChangesViewModel; }
set { SetValue(ViewModelProperty, value); }
}
}
```
NuGet package version:
[Microsoft.WinUI 3.0.0-preview1.200515.3]
| Device form factor | Saw the problem? |
| :-------------------- | :------------------- |
| Desktop | Yes |
| Mobile | |
| Xbox | |
| Surface Hub | |
| IoT | |
@tomasfabian thanks for the report, can you clarify what does not work means. You are seeing the wrong value, or no value at all, ect. Any additional feedback to help us understand the issue fully. Thanks.
@StephenLPeters not at all, I'm glad that I can help the WinUI team.
I'm attaching a solution which simulates the above mentioned issues. By not working I mean that the textbox text is not refreshed in the UI and the button commands are not executed or CanExecute is not evaluated.
Steps to reproduce the issues in the sample:
Buttons are reseting the property value in the VM bound to the corresponding TextBox.Text
1) first section in the example demonstrates that the MyTextBox2.Text is not refreshed in the UI. Button with content "Command is not executed" does not call MyViewModel.AddNew.Execute.
2) the second section demonstrates a nested ViewModel set only after a user action, in this case after "Set Nested ViewModel" button clicked. Before this action all bellow buttons should be disabled, but they are active. After the NestedViewModel property was initialized, only the button with x:Bind and Mode=OneWay can be executed.
Hopefully this will help.
I also found a problem with ObservableCollection notifications, but it has already been reported in another issue.
<!-- Command x:Bind on nested property does not work without Mode -->
<Button Command="{x:Bind ViewModel.ListViewModel.ClearFilter}" Content="xBindWithoutMode" />
The default BindingMode for x:Bind is OneTime, see https://docs.microsoft.com/en-us/windows/uwp/xaml-platform/x-defaultbindmode-attribute.
Further I guess "legacy" Bindings still use the DataContext DP as default source. You did not set the DataContext DP, did you?
However, I've noticed the Issue myself, too. My experience is that legacy bindings do not update the target property, when the the PropertyChanged event is raised, regardless of setting the DataContext property or not.
@Ratcha9 thx for your insight.
I converted a WPF app to a WinUI 3 Desktop app. That's why I also tested "legacy" bindings. WPF doesn't have x:Bind. The default mode in .Net Framework < 4.5 was TwoWay, if I remember it correctly. Nowadays it is OneWay (also in .Net Core WPF) AFAIK.
UWP mode OneTime is maybe too restrictive, at least for MVVM apps. For ICommands its unusable as I found out. On the other hand it could be good enough for MVU refreshes, but I didn't try it.
I didn't set the DataContext, I expected a default Binding. Is it something similar to WPF, where it was necessary to set the Content of ContentControls?
<ContentControl Content="{Binding}"
ContentTemplate="{TemplateBinding RightSideContentTemplate}" />
Edit:
I was thinking about my previous statement and I don't want to confuse anyone, so long story short:
During the migration to .net 4.7 from 4.5 we encountered an issue with two way bindings. The real problem was probably that we used Two way bindings with read only properties and the previous versions of WPF didn't complain about this bug. Sorry I went through too many transitions among different versions of different platforms during my carrer. My mind is not a blank slate anymore. We need Uno platform... Thank you for your understanding
@StephenLPeters I tried to override the default BindMode based on the UWP documentation @Ratcha9 posted.
<UserControl x:Class="Bindings.Views.TestUserControl"
x:DefaultBindMode="OneWay"
Please try it out in the solution I attached. In the TestUserControl it enabled the button with content xBindWithoutMode, but only for one time. Actually the "xBindWithOneWayMode" button was disabled after first click, too. Thank you
@StephenLPeters my mistake. It was disabled due to CanExecute. It works correcly, I apologize.
Edit:
See bellow
x:DefaultBindMode="OneWay" works correctly
Hey no problem, if I'm reading the thread right does that mean your issue is resolved or are there still outstanding issues beyond the "OneTime is maybe not the correct default" issue?
My experience is that legacy bindings do not update the target property, when the the PropertyChanged event is raised, regardless of setting the DataContext property or not.
@StephenLPeters {Binding} still doesn't work for me. The initial value is correct, but it does not update.
You may examine https://github.com/Ratcha9/winui_inpc.
@StephenLPeters I think that the "UWP" x:Bind works correctly in case that OneTime is the default mode (chosen for performance reasons). I didn't have experience with x:Bind. We all should realize that we are coming from different target frameworks. I'm a big fan of unification.... so I'm super excited....
I still think that the "classical" Bindings are not working correcly.
I still think that the "classical" Bindings are not working correcly.
@tomasfabian I'm ramping up on this thread now. Can you clarify that? I get the confusion over the default of OneTime (certainly that one has tripped me up many times). This issue was raised against WinUI3 preview - do you observe the same behavior with inbox UWP XAML (not using WinUI3)? As in, are you seeing a regression relative to UWP, or a lack of unification relative to where you started (WPF)? That matters for us in if this is a bug report (regression from inbox XAML), or a feature request (unification needed, yes please).
@chrisglein we provided you example solutions, you can try them.
I still think that the "classical" Bindings are not working correcly.
I further investigated this issue. It looks like that the bound view model property initially sets the value in the UI with OneTime mode (or it is pulled from VM to UI). After that the bound view model property is only refreshed from the UI like in OneWayToSource mode. The direct update of VM property does not refresh the UI anymore.
In my opinion in case of "classical" Bindings the view doesn't hook/listen to the PropertyChange event, even if I explicitly set TwoWay or OneWay binding in the XAML.
I tried the same code in Blank app (Universal Windows) and there it is working perfectly. So from this point of view it looks like a regression bug.
Hopefully this will help.
This command was not bound neither. I don't know whether it is due to the ViewModel dependency property or because it is a nested property. But this one doesn't work neither in Blank app (Universal Windows):
<Button Command="{Binding ViewModel.Update}"/>
```C#
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(nameof(ViewModel),
typeof(MainViewModel),
typeof(MainPage),
new PropertyMetadata(null));
public MainViewModel ViewModel
{
get => GetValue(ViewModelProperty) as MainViewModel;
set => SetValue(ViewModelProperty, value);
}
```
And commands bound to null values shouldn't be disabled?
Hi, I was trying to run https://github.com/Ratcha9/winui_inpc but it fails on launch. Any idea?
This is fixed in WinUI3 Preview2. Thanks!
Most helpful comment
@StephenLPeters {Binding} still doesn't work for me. The initial value is correct, but it does not update.
You may examine https://github.com/Ratcha9/winui_inpc.