【问题标题】:UWP databinding in an inherited control继承控件中的 UWP 数据绑定
【发布时间】:2021-05-19 06:59:18
【问题描述】:

我有一个从默认 TextBox 继承的自定义文本框控件。在样式上,我添加了一些额外的 xaml,其中之一就是这个进度环:

 <toolkit:Loading    x:Name="IsBusyLoader"
                     Grid.Column="1"
                     Grid.ColumnSpan="2"
                     Style="{StaticResource DefaultLoader}">
        <ProgressRing Style="{StaticResource SmallRing}" />
 </toolkit:Loading>

我必须通过使用控件的绑定来控制它的“IsLoading”。为此,我在此控件后面的代码中创建了它的绑定,因为它是一种样式,所以我不确定如何使用依赖属性以 xaml 样式创建该绑定。

        public FluentTextBox() => DefaultStyleKey = typeof(FluentTextBox);

    protected override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        //GetTemplateChild
        _isBusyLoader = GetTemplateChild("IsBusyLoader") as Loading;

        //bindings
        _isBusyLoader.SetBinding(Microsoft.Toolkit.Uwp.UI.Controls.Loading.IsLoadingProperty, new Binding { Mode = BindingMode.OneWay, Source = IsBusy });
    }

    public bool IsBusy
    {
        get => (bool) GetValue(IsBusyProperty);
        set => SetValue(IsBusyProperty, value);
    }
    public static readonly DependencyProperty IsBusyProperty =
        DependencyProperty.Register("IsBusy", typeof(bool), typeof(FluentTextBox), new PropertyMetadata(null));

如您所见,IsBusy 是一个依赖属性。我在 UI 上绑定到它,我正在使用这个自定义文本框。

<controls1:FluentTextBox
                Margin="4"
                Header="Field 1"
                IsBusy="{x:Bind IsBusy, Mode=OneWay}" />

现在这里的 IsBusy 属性实际上在代码中,问题是当我从后面的代码更新 IsBusy 属性时,它不会反映在 UI 中。但是我在该页面的其他地方使用了相同的 IsBusy 属性,并且它在那里正确地向 UI 发出通知,所以我很清楚该部分工作正常。

 public bool IsBusy // code behind is busy property on my xaml page.
    {
        get => _isBusy;
        set
        {
            _isBusy = value;
            RaisePropertyChanged(nameof(IsBusy));
        }
    }

请注意,当我在源代码中创建绑定并将其设置为“true”时,我的自定义文本框会按预期显示进度环。我也尝试将源绑定到 IsBusyProperty ,但这也不起作用。

_isBusyLoader.SetBinding(Microsoft.Toolkit.Uwp.UI.Controls.Loading.IsLoadingProperty, new Binding { Mode = BindingMode.OneWay, Source = true });

更新 1

完整样式代码

<Style TargetType="controls:FluentTextBox">
    <Setter Property="Margin" Value="{ThemeResource DefaultControlMargin}" />
    <Setter Property="local:TextBoxProperties.Initialized" Value="true" />
    <Setter Property="MinWidth" Value="{ThemeResource TextControlThemeMinWidth}" />
    <Setter Property="MinHeight" Value="{ThemeResource TextControlThemeMinHeight}" />
    <Setter Property="Foreground" Value="{ThemeResource TextControlForeground}" />
    <Setter Property="Background" Value="{ThemeResource TextControlBackground}" />
    <Setter Property="BorderBrush" Value="{ThemeResource TextControlBorderBrush}" />
    <Setter Property="SelectionHighlightColor" Value="{ThemeResource TextControlSelectionHighlightColor}" />
    <Setter Property="BorderThickness" Value="{ThemeResource TextControlBorderThemeThickness}" />
    <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
    <Setter Property="FontSize" Value="{ThemeResource InputControlFontSize}" />
    <Setter Property="ScrollViewer.HorizontalScrollMode" Value="Auto" />
    <Setter Property="ScrollViewer.VerticalScrollMode" Value="Auto" />
    <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Hidden" />
    <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Hidden" />
    <Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="False" />
    <Setter Property="HorizontalAlignment" Value="{ThemeResource DefaultControlHorizontalAlignment}" />
    <Setter Property="VerticalAlignment" Value="{ThemeResource DefaultControlVerticalAlignment}" />
    <Setter Property="Padding" Value="{ThemeResource TextControlThemePadding}" />
    <Setter Property="UseSystemFocusVisuals" Value="{ThemeResource IsApplicationFocusVisualKindReveal}" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="controls:FluentTextBox">
                <Grid>
                    <Grid.Resources>
                        <!--default delete button style here-->
                    </Grid.Resources>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*" />
                        <ColumnDefinition Width="Auto" />
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="*" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <i:Interaction.Behaviors>
                        <ic:EventTriggerBehavior EventName="PointerEntered">
                            <ic:CallMethodAction MethodName="StartAnimation" TargetObject="{Binding ElementName=MoreActionGridFadeIn}" />
                        </ic:EventTriggerBehavior>
                        <ic:EventTriggerBehavior EventName="PointerExited">
                            <ic:CallMethodAction MethodName="StartAnimation" TargetObject="{Binding ElementName=MoreActionGridFadeOut}" />
                        </ic:EventTriggerBehavior>
                    </i:Interaction.Behaviors>
                    <Border
                        x:Name="BorderElement"
                        Grid.Row="0"
                        Grid.RowSpan="3"
                        Grid.ColumnSpan="2"
                        MinWidth="{ThemeResource TextControlThemeMinWidth}"
                        MinHeight="{ThemeResource TextControlThemeMinHeight}"
                        Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}"
                        Control.IsTemplateFocusTarget="True"
                        CornerRadius="{TemplateBinding CornerRadius}" />
                    <Border
                        x:Name="ValidationBorder"
                        Grid.Row="0"
                        Grid.RowSpan="3"
                        Grid.ColumnSpan="2"
                        MinWidth="{ThemeResource TextControlThemeMinWidth}"
                        MinHeight="{ThemeResource TextControlThemeMinHeight}"
                        BorderBrush="{ThemeResource ValidationBorderBrush}"
                        CornerRadius="{TemplateBinding CornerRadius}" />
                    <ContentPresenter
                        x:Name="ShadowHeaderContentPresenter"
                        Padding="10,0,2,0"
                        Background="{x:Null}"
                        Content="{TemplateBinding Header}"
                        ContentTemplate="{TemplateBinding HeaderTemplate}"
                        FontSize="{TemplateBinding FontSize}"
                        FontWeight="Normal"
                        Foreground="{x:Null}"
                        Opacity="0"
                        TextWrapping="NoWrap"
                        Visibility="Visible" />
                    <ContentPresenter
                        x:Name="HeaderContentPresenter"
                        Padding="10,0,2,0"
                        x:DeferLoadStrategy="Lazy"
                        Content="{TemplateBinding Header}"
                        ContentTemplate="{TemplateBinding HeaderTemplate}"
                        FontSize="{TemplateBinding FontSize}"
                        FontWeight="Normal"
                        Foreground="{Binding ElementName=PlaceholderTextContentPresenter, Path=Foreground, Mode=OneWay}"
                        TextWrapping="NoWrap"
                        Visibility="Collapsed">
                        <ContentPresenter.RenderTransform>
                            <CompositeTransform />
                        </ContentPresenter.RenderTransform>
                    </ContentPresenter>
                    <ScrollViewer
                        x:Name="ContentElement"
                        Grid.Row="1"
                        Margin="{TemplateBinding BorderThickness}"
                        Padding="{TemplateBinding Padding}"
                        AutomationProperties.AccessibilityView="Raw"
                        HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
                        HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}"
                        IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}"
                        IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}"
                        IsTabStop="False"
                        IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}"
                        VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"
                        VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}"
                        ZoomMode="Disabled" />
                    <TextBlock
                        x:Name="PlaceholderTextContentPresenter"
                        Grid.Row="1"
                        Grid.ColumnSpan="2"
                        Margin="{TemplateBinding BorderThickness}"
                        Padding="10,0,0,0"
                        Foreground="{Binding PlaceholderForeground, RelativeSource={RelativeSource TemplatedParent}, TargetNullValue={ThemeResource TextControlPlaceholderForeground}}"
                        IsHitTestVisible="False"
                        Text="{TemplateBinding PlaceholderText}"
                        TextAlignment="{TemplateBinding TextAlignment}"
                        TextWrapping="{TemplateBinding TextWrapping}" />
                    <Grid Grid.RowSpan="3" Grid.Column="1">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="Auto" />
                        </Grid.ColumnDefinitions>
                        <Button
                            x:Name="DeleteButton"
                            MinWidth="{ThemeResource DeleteButtonMinWidth}"
                            MaxWidth="{ThemeResource DeleteButtonMaxWidth}"
                            Margin="{ThemeResource HelperButtonThemePadding}"
                            VerticalAlignment="Stretch"
                            AutomationProperties.AccessibilityView="Raw"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            FontSize="{TemplateBinding FontSize}"
                            IsTabStop="False"
                            Style="{StaticResource DeleteButtonStyle}"
                            Visibility="Collapsed" />
                        <Grid x:Name="ActionGrid" Grid.Column="1">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="48" />
                                <ColumnDefinition Width="48" />
                            </Grid.ColumnDefinitions>
                            <Grid>
                                <Grid x:Name="MoreGrid" Opacity="0">
                                    <i:Interaction.Behaviors>
                                        <ToolkitBehaviors:Fade
                                            x:Name="MoreActionGridFadeIn"
                                            AutomaticallyStart="False"
                                            Delay="0"
                                            EasingMode="EaseOut"
                                            EasingType="Cubic"
                                            Value="1"
                                            Duration="300" />
                                        <ToolkitBehaviors:Fade
                                            x:Name="MoreActionGridFadeOut"
                                            AutomaticallyStart="False"
                                            Delay="0"
                                            EasingMode="EaseOut"
                                            EasingType="Cubic"
                                            Value="0"
                                            Duration="300" />
                                    </i:Interaction.Behaviors>
                                    <AppBarButton
                                        x:Name="CopyButton"
                                        Width="48"
                                        Height="48"
                                        HorizontalAlignment="Center"
                                        VerticalAlignment="Center"
                                        Icon="Copy"
                                        ToolTipService.ToolTip="Copy" />
                                </Grid>
                            </Grid>
                            <Grid Grid.Column="1">
                                <toolkit:DropShadowPanel
                                    Width="24"
                                    Height="24"
                                    Margin="8"
                                    HorizontalAlignment="Center"
                                    VerticalAlignment="Center"
                                    Style="{StaticResource GridShadowSmall}"
                                    Color="Black">
                                    <Ellipse
                                        Width="24"
                                        Height="24"
                                        HorizontalAlignment="Center"
                                        VerticalAlignment="Center"
                                        Fill="{TemplateBinding BorderBrush}" />
                                </toolkit:DropShadowPanel>
                                <Ellipse
                                    x:Name="CentralElipse"
                                    Width="20"
                                    Height="20"
                                    HorizontalAlignment="Center"
                                    VerticalAlignment="Center"
                                    Canvas.ZIndex="10">
                                    <ToolTipService.ToolTip>
                                        <ToolTip>
                                            <Grid Width="140" MaxHeight="200">
                                                <Grid.RowDefinitions>
                                                    <RowDefinition Height="Auto" />
                                                    <RowDefinition />
                                                </Grid.RowDefinitions>
                                                <Grid.ColumnDefinitions>
                                                    <ColumnDefinition Width="Auto" />
                                                    <ColumnDefinition />
                                                </Grid.ColumnDefinitions>
                                                <TextBlock
                                                    x:Name="MemosCountBlock"
                                                    Grid.Row="1"
                                                    Margin="4"
                                                    FontWeight="SemiBold"
                                                    TextTrimming="CharacterEllipsis"
                                                    TextWrapping="Wrap" />
                                                <TextBlock
                                                    Grid.Row="1"
                                                    Grid.Column="1"
                                                    Margin="4"
                                                    Text="Memos"
                                                    TextTrimming="CharacterEllipsis"
                                                    TextWrapping="WrapWholeWords" />
                                                <TextBlock
                                                    x:Name="MyFirstMemoBlock"
                                                    Grid.ColumnSpan="2"
                                                    Margin="4"
                                                    TextTrimming="CharacterEllipsis"
                                                    TextWrapping="WrapWholeWords" />
                                            </Grid>
                                        </ToolTip>
                                    </ToolTipService.ToolTip>
                                    <FlyoutBase.AttachedFlyout>
                                        <Flyout x:Name="MemosFlyout" FlyoutPresenterStyle="{StaticResource NoPaddingFlyoutPresenter}">
                                            <local1:MemosControl
                                                x:Name="MyMemosControl"
                                                Width="320"
                                                MaxHeight="440"
                                                Padding="0,8,0,0"
                                                NewMemoButtonVisible="True" />
                                        </Flyout>
                                    </FlyoutBase.AttachedFlyout>
                                </Ellipse>
                            </Grid>
                            <toolkit:Loading
                                x:Name="IsBusyLoader"
                                Grid.ColumnSpan="2"
                                Style="{StaticResource DefaultLoader}">
                                <ProgressRing Style="{StaticResource SmallRing}" />
                            </toolkit:Loading>
                        </Grid>
                    </Grid>

                    <ContentPresenter
                        x:Name="DescriptionPresenter"
                        Grid.Row="2"
                        Padding="10,0,4,4"
                        x:Load="False"
                        AutomationProperties.AccessibilityView="Raw"
                        Content="{TemplateBinding Description}"
                        FontSize="{StaticResource InputControlHeaderFontSize}"
                        Foreground="{Binding ElementName=PlaceholderTextContentPresenter, Path=Foreground, Mode=OneWay}" />



                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">

                            <VisualState x:Name="Disabled">
                           <!--  default disabled state  -->
                                
                            </VisualState>
                            <VisualState x:Name="Normal" />

                            <VisualState x:Name="PointerOver">

                                <!--  default pointer over state  -->
                            </VisualState>
                            <VisualState x:Name="Focused">

                                <!--  default focused state  -->
                            </VisualState>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="ButtonStates">
                            <VisualState x:Name="ButtonVisible">

                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="DeleteButton" Storyboard.TargetProperty="Visibility">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <Visibility>Visible</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="ButtonCollapsed" />
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="HeaderStates">
                            <VisualStateGroup.Transitions>
                                <VisualTransition GeneratedDuration="0:0:0.25">
                                    <VisualTransition.GeneratedEasingFunction>
                                        <CircleEase EasingMode="EaseInOut" />
                                    </VisualTransition.GeneratedEasingFunction>
                                </VisualTransition>
                            </VisualStateGroup.Transitions>
                            <VisualState x:Name="NotEmpty">
                                <VisualState.Setters>
                                    <Setter Target="HeaderContentPresenter.(FontSize)" Value="{StaticResource InputControlHeaderFontSize}" />
                                </VisualState.Setters>
                                <VisualState.StateTriggers>
                                    <StateTrigger IsActive="{Binding Text, Converter={StaticResource IsNotEmptyConverter}, Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}}" />
                                </VisualState.StateTriggers>
                            </VisualState>
                            <VisualState x:Name="Empty">
                                <VisualState.Setters>
                                    <Setter Target="HeaderContentPresenter.(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Value="16" />
                                    <Setter Target="PlaceholderTextContentPresenter.(Opacity)" Value="0" />
                                </VisualState.Setters>
                                <VisualState.StateTriggers>
                                    <StateTrigger IsActive="{Binding Text, Converter={StaticResource IsEmptyConverter}, Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}}" />
                                </VisualState.StateTriggers>
                            </VisualState>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="ValidationStates">
                            <VisualStateGroup.Transitions>
                                <VisualTransition GeneratedDuration="0:0:0.25">
                                    <VisualTransition.GeneratedEasingFunction>
                                        <CircleEase EasingMode="EaseInOut" />
                                    </VisualTransition.GeneratedEasingFunction>
                                </VisualTransition>
                            </VisualStateGroup.Transitions>
                            <VisualState x:Name="Valid" />
                            <VisualState x:Name="NotValid">
                                <VisualState.Setters>
                                    <Setter Target="ValidationBorder.(BorderThickness)" Value="{ThemeResource ValidationBorderThickness}" />

                                </VisualState.Setters>
                                <VisualState.StateTriggers>
                                    <StateTrigger IsActive="{Binding (local:Validation.HasError), Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}}" />
                                </VisualState.StateTriggers>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

【问题讨论】:

  • 您能否为您的FluentTextBox 控件发布Style,包括模板?
  • @mm8 添加。我已经删除了一些无关紧要的代码,因为它超出了这里的字符限制,并且我已经评论了我删除代码的地方,它的大部分是默认代码,所以不会很重要

标签: c# xaml uwp binding styles


【解决方案1】:

您应该能够直接绑定到您的ControlTemplate 中的IsBusy 属性,而不是覆盖OnApplyTemplate()

<toolkit:Loading x:Name="IsBusyLoader" IsLoading="{x:Bind IsBusy, Mode=TwoWay}" ... />

请注意,您应该设置 Mode 属性,因为编译 (x:Bind) 绑定的默认模式是 OneTime

您还应该在注册依赖属性时指定一个有效的默认值:

public static readonly DependencyProperty IsBusyProperty =
    DependencyProperty.Register(nameof(IsBusy), typeof(bool), typeof(FluentTextBox),
    new PropertyMetadata(false));

【讨论】:

  • x:Bind 在资源字典中不起作用,并且这种样式在资源字典中,如果它是用户控件,那么我可以将 x:Bind 直接绑定到 xaml 中的 IsBusy 属性,但事实并非如此继承控制
  • @touseefbsb:什么? x:Bind 确实在资源字典中定义的 ControlTemplates 中工作。你在说什么?
猜你喜欢
  • 2020-01-24
  • 2021-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-16
  • 1970-01-01
  • 2018-04-13
相关资源
最近更新 更多