I am currently trying to bind a textbox conditionally based on 3 different objects depending on a Level enum value. In the code sample below, what I hoping to achieve is to display values depending on the following condition:
- Person Level0, bind/display ViewModel.Person.Level0.Name
- Person Level1, bind/display ViewModel.Person.Level1.Name
- Person Level2, bind/display ViewModel.Person.Level2.Name
With all that, the problem i have is that not of the objects are displaying as i am hoping. The textbox remains empty, with no values on display. What am i doing wrong?
<TextBox Margin="0,0,0,5">
<interactivity:Interaction.Behaviors>
<core:DataTriggerBehavior Binding="{x:Bind ViewModel.Person.Level, FallbackValue='', Mode=OneWay}" ComparisonCondition="Equal" Value="Level0">
<core:ChangePropertyAction PropertyName="Text" Value="{x:Bind ViewModel.Person.Level0.Name, FallbackValue=''}" />
</core:DataTriggerBehavior>
<core:DataTriggerBehavior Binding="{x:Bind ViewModel.Person.Level, FallbackValue='', Mode=OneWay}" ComparisonCondition="Equal" Value="Level1">
<core:ChangePropertyAction PropertyName="Text" Value="{x:Bind ViewModel.Person.Level1.Name, FallbackValue='', Mode=OneWay}" />
</core:DataTriggerBehavior>
<core:DataTriggerBehavior Binding="{x:Bind ViewModel.Person.Level, FallbackValue='', Mode=OneWay}" ComparisonCondition="Equal" Value="Level2">
<core:ChangePropertyAction PropertyName="Text" Value="{x:Bind ViewModel.Person.Level2.Name, FallbackValue='', Mode=OneWay}" />
</core:DataTriggerBehavior>
</interactivity:Interaction.Behaviors>
</TextBox>
CodePudding user response:
This should work.
Notes:
- This code uses a
string
instead ofLevel
in thePerson
class becauseenum
binding seems not to work (I'm not sure) withChangePropertyAction
. - The MainPage is named as "ThisPage" so we can bind the ViewModel inside the
ChangePropertyAction
.
MainPage.xaml
<Page
x:Class="ConditionalBindingTest.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:local="using:ConditionalBindingTest"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Name="ThisPage"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
mc:Ignorable="d">
<Grid>
<TextBox>
<interactivity:Interaction.Behaviors>
<core:DataTriggerBehavior
Binding="{x:Bind ViewModel.Person.Level, Mode=OneWay}"
ComparisonCondition="Equal"
Value="Level0">
<core:ChangePropertyAction
PropertyName="Text"
Value="{Binding ElementName=ThisPage, Path=ViewModel.Person.Level0.Name, Mode=OneWay}" />
</core:DataTriggerBehavior>
<core:DataTriggerBehavior
Binding="{x:Bind ViewModel.Person.Level, Mode=OneWay}"
ComparisonCondition="Equal"
Value="Level1">
<core:ChangePropertyAction
PropertyName="Text"
Value="{Binding ElementName=ThisPage, Path=ViewModel.Person.Level1.Name, Mode=OneWay}" />
</core:DataTriggerBehavior>
</interactivity:Interaction.Behaviors>
</TextBox>
</Grid>
</Page>
MainPage.xaml.cs
using Microsoft.UI.Xaml.Controls;
namespace ConditionalBindingTest;
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
public MainPageViewModel ViewModel { get; } = new();
}
MainPageViewModel.cs
using CommunityToolkit.Mvvm.ComponentModel;
namespace ConditionalBindingTest;
public enum Level
{
Level0,
Level1,
}
public class LevelName
{
public LevelName(Level level)
{
Name = $"{level} Name";
}
public string Name { get; }
}
public class Person
{
public string Level { get; } = ConditionalBindingTest.Level.Level0.ToString();
public LevelName Level0 { get; } = new(ConditionalBindingTest.Level.Level0);
public LevelName Level1 { get; } = new(ConditionalBindingTest.Level.Level1);
}
public partial class MainPageViewModel : ObservableObject
{
[ObservableProperty]
private Person person = new();
}
CodePudding user response:
What am i doing wrong?
- You use
x:Bind
where it's not supported - You implement logic in the XAML markup of the view
x:Bind
directly to another read-only property of the view model that is defined something like this:
public string DisplayValue
{
get
{
switch (Person.Level)
{
case "Level0":
return Person.Level0.Name;
case "Level1":
return Person.Level1.Name;
case "Level2":
return Person.Level2.Name;
}
return string.Empty;
}
}
C# is a much more expressive, more concise language than XAML, and while it may be possible to create an entire fairly complex view in markup only, it doesn't mean that it's always a good idea doing so. In this case, you should move the logic to the view model or the Person
class itself.