【问题标题】:How to bind foreground property of a control to another control foreground如何将控件的前景属性绑定到另一个控件前景
【发布时间】:2021-12-30 16:51:46
【问题描述】:

当超链接按钮控件作为项目添加到列表视图时,我试图解决它的问题。

当项目没有被选中时控件显示得很好(默认前景是黑色),但是一旦列表视图项目被选中,它的内容背景就会变成深蓝色,使得里面的任何黑色文本都很难阅读,出于这个原因,列表视图项内的任何文本块控件,其前景属性(文本颜色)自动更改为白色(这是默认系统行为),问题是,同样的事情不会发生在里面的超链接按钮那说列表视图项。

请注意,超链接按钮在没有像文本块一样被选中时具有透明背景,但前景色始终保持黑色,无论是否选择了包含它的列表视图项。

为了克服这个问题,我尝试在超链接按钮内容中创建一个文本块以显示文本并将其前景属性绑定到列表视图项内的另一个文本块,默认情况下会正确更改其前景,但绑定似乎不起作用,它只设置一次值,然后不再更新,无论何时选择或取消选择列表视图项,绑定都不会反映源代码管理前景属性的当前前景值。

我在下面为您提供了一个示例代码来重现我的问题。

        <ListView x:Name="Employees_List_View" BorderThickness="1" BorderBrush="{ThemeResource SystemControlForegroundBaseMediumLowBrush}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
              SelectionMode="Extended" ItemsSource="{x:Bind contact_data_model.contacts}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <Grid Height="50" Margin="0 7 0 7">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="50"/>
                        <ColumnDefinition Width="80"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="20"/>
                        <RowDefinition Height="30"/>
                    </Grid.RowDefinitions>
                    <TextBlock FontWeight="Bold" FontSize="16" Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2" Text="{Binding Name}"></TextBlock>
                    <TextBlock  x:Name="TelelphoneNumberTextBlock" FontSize="12" Grid.Row="1" Grid.Column="1" Text="{Binding TelephoneNumber}" VerticalAlignment="Center"/>
                    <HyperlinkButton  VerticalAlignment="Center" HorizontalAlignment="Center" Click="HyperlinkButton_Click" FontSize="12" Grid.Row="1" Grid.Column="2">
                        <TextBlock Opacity="1" Foreground="{Binding Foreground, ElementName=TelelphoneNumberTextBlock, Mode=OneWay}" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="12" Grid.Row="1" Grid.Column="2" Text="{Binding EmailInfo}"/>
                    </HyperlinkButton>
                </Grid>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

我的问题可能很容易解决,但我搜索了很多,但没有成功找到解决这个特定问题的方法。

我能想出的摆脱这种情况的唯一方法是将其位于超链接按钮不透明度内的文本块设置为 0(因此超链接按钮自动调整大小仍按预期工作)并在按钮顶部创建一个新文本块与按钮本身相同的文本和位置,例如:

...
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="12" Grid.Row="1" Grid.Column="2" Text="{Binding EmailInfo}"/>
<HyperlinkButton VerticalAlignment="Center" HorizontalAlignment="Center" Click="HyperlinkButton_Click" FontSize="12" Grid.Row="1" Grid.Column="2">
    <TextBlock Opacity="0" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="12" Grid.Row="1" Grid.Column="2" Text="{Binding EmailInfo}"/>
</HyperlinkButton>
...

这个解决方案是丑陋和骇人听闻的。 我很肯定这个问题有一个更优雅的解决方案,但我搜索的所有内容都没有触及这个非常具体的问题,而且我的 xaml 知识非常有限。

针对此问题的正确 XAML 解决方案是什么?

【问题讨论】:

    标签: c# xaml uwp winui-3


    【解决方案1】:

    更新:

    以下是选择 ListViewItem 时更改 HyperlinkBtn 前景色的步骤。

    1. 您需要为 HyperlinkBut​​ton 命名,例如 HyperlinkBtn,以便您可以在 ListView.SelectionChanged event 中找到 HyperlinkBut​​ton。
    2. 创建一个变量,用于保存最后选择的 HyperlinkBut​​ton。
    3. 您可以在 SelectionChanged 事件中获取所选项目,现在您可以根据需要更改其前景色。
    4. 将之前选择的项目颜色改回正常颜色。

    下面是你可以参考的代码:

     public HyperlinkButton previousItem { get; set; }
    
      private void Employees_List_View_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var _Container = Employees_List_View.ContainerFromItem(Employees_List_View.SelectedItem);
            //get the hyperlink button
            var HyperlinkBtn = (HyperlinkButton)FindMyChildByName(_Container, "HyperlinkBtn");
            // change the foreground as you want
            HyperlinkBtn.Foreground = new SolidColorBrush(Colors.Green);
            if (previousItem != null) 
            {
                //change the previous one back to red color if there is a previous one
                previousItem.Foreground= new  SolidColorBrush(Colors.Red);
            }
            //record the new Item as previousItem
            previousItem = HyperlinkBtn;
        }
    
    
        public static DependencyObject FindMyChildByName(DependencyObject parant, string ControlName)
        {
            int count = VisualTreeHelper.GetChildrenCount(parant);
    
            for (int i = 0; i < count; i++)
            {
                var MyChild = VisualTreeHelper.GetChild(parant, i);
                if (MyChild is FrameworkElement && ((FrameworkElement)MyChild).Name == ControlName)
                    return MyChild;
    
                var FindResult = FindMyChildByName(MyChild, ControlName);
                if (FindResult != null)
                    return FindResult;
            }
    
            return null;
        }
    

    对于您的方案,我建议您覆盖 HyperlinkBut​​ton 的默认样式。您可以将样式中 HyperlinkBut​​ton 的前景色更改为您想要的任何颜色。您还可以更改样式中 HyperlinkBut​​ton 的其他行为。

    这是我做的例子,我已经改变了不同状态的前景色。正常时为红色,指针悬停时为黄色,按下时为蓝色。

    Xaml:

      <Page.Resources>
        <Style x:Key="HyperlinkButtonStyle1" TargetType="HyperlinkButton">
            <Setter Property="Background" Value="{ThemeResource HyperlinkButtonBackground}"/>
            <Setter Property="BackgroundSizing" Value="OuterBorderEdge"/>
            <Setter Property="Foreground" Value="Red"/>
            <Setter Property="BorderBrush" Value="{ThemeResource HyperlinkButtonBorderBrush}"/>
            <Setter Property="BorderThickness" Value="{ThemeResource HyperlinkButtonBorderThemeThickness}"/>
            <Setter Property="Padding" Value="{StaticResource HyperlinkButtonPadding}"/>
            <Setter Property="HorizontalAlignment" Value="Left"/>
            <Setter Property="VerticalAlignment" Value="Center"/>
            <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}"/>
            <Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}"/>
            <Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}"/>
            <Setter Property="FocusVisualMargin" Value="-3"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="HyperlinkButton">
                        <ContentPresenter x:Name="ContentPresenter" AutomationProperties.AccessibilityView="Raw" 
                                          BackgroundSizing="{TemplateBinding BackgroundSizing}"
                                          Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}"
                                          BorderBrush="{TemplateBinding BorderBrush}"
                                          ContentTemplate="{TemplateBinding ContentTemplate}"
                                          Content="{TemplateBinding Content}" CornerRadius="{TemplateBinding CornerRadius}" 
                                          ContentTransitions="{TemplateBinding ContentTransitions}" 
                                          HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}">
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="CommonStates">
                                    <VisualState x:Name="Normal"/>
                                    <VisualState x:Name="PointerOver">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="Yellow"/>
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource HyperlinkButtonBackgroundPointerOver}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource HyperlinkButtonBorderBrushPointerOver}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Pressed">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="Blue"/>
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource HyperlinkButtonBackgroundPressed}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource HyperlinkButtonBorderBrushPressed}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Disabled">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource HyperlinkButtonForegroundDisabled}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource HyperlinkButtonBackgroundDisabled}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource HyperlinkButtonBorderBrushDisabled}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                        </ContentPresenter>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Page.Resources>
    

    并像这样使用它:

     <HyperlinkButton Style="{StaticResource HyperlinkButtonStyle1}"  VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="12" Grid.Row="1" Grid.Column="2" Content="{Binding EmailInfo}">
    

    【讨论】:

    • 问候,感谢您提供此示例,但问题不在于指向所述控件时,问题在于更改所选列表视图项容器内的超链接控件的前景。有什么我可以用来设置的吗?我尝试使用您的示例,虽然它非常适合指向和其他事件,但一旦选择了作为列表视图项目一部分的超链接按钮,它就无法正常工作。
    • @EugenM 好的,我误解了你的问题。要实现您想要的行为,您可能需要使用其他一些方法。我已经更新了我的答案,你可以检查一下。
    • 感谢您向我介绍 VisualTree Helper。在这种情况下非常好,我最终这样做了,我不必为不同的状态(指针悬停、正常、单击等)更改多个前景值,正在创建一个文本块作为超链接按钮内的内容(删除第二个现在不必要的文本块)并找到所述文本块内容以仅更改其前景属性(文本块前景不会根据指向,正常,选中而改变,因此更改前景就足够了)。非常感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 2012-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-13
    相关资源
    最近更新 更多