0

The TextBox control (Microsoft.UI.Xaml.Controls.TextBox) exposes an "IsReadonly" property, which seems to differ from !IsEnabled in the following ways:

  • The content of a ReadOnly TextBox can be selected
  • A ReadOnly TextBox is a tab stop by default
  • ReadOnly TextBoxes are initially visually indistinct from Non-ReadOnly TextBoxes

Other textbox-like controls, such as the NumberBox and AutoSuggestBox, have no such property. Is there any way to convince other controls that are visually similar to a TextBox to have ReadOnly behaviour?

1 Answer 1

1

AutoSuggestBox and NumberBox have an inner TextBox. You can access it with the CommunityToolkit.WinUI.Extensions's FindDescendant().

For example, you can create an AttachedProperty like this:

public static class Extensions
{
    public static readonly DependencyProperty IsReadOnlyProperty =
        DependencyProperty.RegisterAttached(
            "IsReadOnly",
            typeof(bool),
            typeof(Extensions),
            new PropertyMetadata(default, OnIsReadOnlyPropertyChanged));

    public static bool GetIsReadOnly(DependencyObject obj) => (bool)obj.GetValue(IsReadOnlyProperty);

    public static void SetIsReadOnly(DependencyObject obj, bool value) => obj.SetValue(IsReadOnlyProperty, value);

    private static void OnIsReadOnlyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is not FrameworkElement element)
        {
            return;
        }

        element.Loaded -= Element_Loaded;

        if (element.IsLoaded is false)
        {
            element.Loaded += Element_Loaded;
            return;
        }

        _ = TryUpdateIsReadOnly(element);
    }

    private static void Element_Loaded(object sender, RoutedEventArgs e)
    {
        _ = TryUpdateIsReadOnly(sender);
    }

    private static bool TryUpdateIsReadOnly(object sender)
    {
        if (sender is not FrameworkElement element ||
            element.FindDescendant<TextBox>() is not TextBox innerTextBox)
        {
            return false;
        }

        innerTextBox.IsReadOnly = GetIsReadOnly(element);
        System.Diagnostics.Debug.WriteLine($"{element.GetType()} IsReadOnly: {innerTextBox.IsReadOnly}");
        return true;
    }
}

Then use it like this:

<StackPanel Spacing="8">
    <ToggleSwitch
        x:Name="IsReadOnlyToggleSwitch"
        Header="IsReadOnly"
        OffContent="False"
        OnContent="True" />
    <TextBox
        IsReadOnly="{x:Bind IsReadOnlyToggleSwitch.IsOn, Mode=OneWay}"
        Text="TextBox" />
    <AutoSuggestBox
        local:Extensions.IsReadOnly="{x:Bind IsReadOnlyToggleSwitch.IsOn, Mode=OneWay}"
        Text="AutoSuggestBox" />
    <NumberBox
        local:Extensions.IsReadOnly="{x:Bind IsReadOnlyToggleSwitch.IsOn, Mode=OneWay}"
        Value="12345" />
</StackPanel>
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.