Search code examples
c#xamlwinui-3

WinUi 3 make enable of an control depends on value of 2 others


I have 2 static checkboxes:

<CheckBox x:Name="CheckOne" Content="I'm one" />
<CheckBox x:Name="CheckTwo" Content="I'm two" />

And collection of checkboxes binded to ObservableCollection:

<ItemsControl ItemsSource="{x:Bind ViewModel.CheckList, Mode=OneWay}">
    <ItemsControl.ItemTemplate>
        <DataTemplate x:DataType="CheckBox">
            <CheckBox Content="{Binding}" IsChecked="True" IsEnabled="False" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl> 

I need checkboxes in ItemsControl be enabled only if CheckOne is checked and CheckTwo is not checked. Is there any way to make this only using Xaml?

I tried to perform it using property in codebehind, something like:

public bool isCheckListEnabled { 
    get {
        if ((bool)this.CheckOne.IsChecked 
            && !(bool)this.CheckTwo.IsChecked)
        {
            return true;
        }
        else
        {
            return false;
        }
    } 
}

And bind it to IsEnabled property of checkboxes in the ItemsControl like:

<CheckBox Content="{Binding}" IsChecked="True" IsEnabled="{x:Bind isCheckListEnabled}" />

But I have warning that "The property isCheckListEnabled was not found in type 'CheckBox'. I assume this is because of <DataTemplate x:DataType="CheckBox">, which means that x: is not Page anymore but CheckBox. How to bind now anything inside of DataTemplate to Page's properties?


Solution

  • In a Page, this doesn't work with Window, you can add a DependencyProperty that represents the status of the CheckBoxes. This is a working example:

    MainPage.xaml

    using Microsoft.UI.Xaml;
    using Microsoft.UI.Xaml.Controls;
    using System.Collections.ObjectModel;
    
    namespace App1;
    
    public sealed partial class MainPage : Page
    {
        public static readonly DependencyProperty EnableCheckBoxesInItemsControlProperty =
            DependencyProperty.Register(
                nameof(EnableCheckBoxesInItemsControl),
                typeof(bool),
                typeof(MainPage),
                new PropertyMetadata(default));
    
        public MainPage()
        {
            this.InitializeComponent();
        }
    
        public bool EnableCheckBoxesInItemsControl
        {
            get => (bool)GetValue(EnableCheckBoxesInItemsControlProperty);
            set => SetValue(EnableCheckBoxesInItemsControlProperty, value);
        }
    
        public ObservableCollection<string> Items { get; set; } = new()
        {
            "A",
            "B",
            "C",
        };
    
        private void CheckBox_CheckChanged(object sender, RoutedEventArgs e)
        {
            this.EnableCheckBoxesInItemsControl = 
                this.CheckBox1.IsChecked is true &&
                this.CheckBox2.IsChecked is true;
        }
    }
    

    MainPage.xaml

    <?xml version="1.0" encoding="utf-8" ?>
    <Page
        x:Class="App1.MainPage"
        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:local="using:App1"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        x:Name="ThisPage"
        Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
        mc:Ignorable="d">
    
        <StackPanel>
            <CheckBox
                x:Name="CheckBox1"
                Checked="CheckBox_CheckChanged"
                Unchecked="CheckBox_CheckChanged" />
            <CheckBox
                x:Name="CheckBox2"
                Checked="CheckBox_CheckChanged"
                Unchecked="CheckBox_CheckChanged" />
            <ItemsControl ItemsSource="{x:Bind Items, Mode=OneWay}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate x:DataType="x:String">
                        <CheckBox
                            Content="{x:Bind}"
                            IsEnabled="{Binding ElementName=ThisPage, Path=EnableCheckBoxesInItemsControl}" />
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </StackPanel>
    
    </Page>
    

    Note that I'm naming the Page ThisPage to do the binding from inside the ItemTemplate. This method should also work with ListView but not with ItemsRepeater.