首页 > 解决方案 > 如何仅将 SelectionChanged 事件绑定到 XAML 中其他元素上的可见性属性

问题描述

给定的是 SelectionChanged 后的 ComboBox 应该成为可见的 TextBlock。我使用 ViemModel 构建此功能。

看法:

<ComboBox SelectionChanged="{mvvmHelper:EventBinding OnSelectionChanged}" />
<TextBlock Visibility="{Binding LanguageChanged, Converter={StaticResource BooleanVisibilityConverter}}"/>

视图模型:

bool LanguageChanged = false;

void OnSelectionChanged() => LanguageChanged = true;

我正在寻找仅在 XAML 中完成的优雅解决方案

到目前为止我尝试了什么:

<Style TargetType="{x:Type TextBlock}">
    <Setter Property="Visibility" Value="Collapsed" />
    <Style.Triggers>
        <DataTrigger Binding="{Binding IsDropDownOpen, ElementName=Box, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" Value="True">
            <Setter Property="Visibility" Value="Visible" />
        </DataTrigger>
    </Style.Triggers>
</Style>

我想我必须使用故事板

<ComboBox.Style>
    <Style TargetType="{x:Type ComboBox}">
        <Style.Triggers>
            <EventTrigger RoutedEvent="SelectionChanged">
                <BeginStoryboard>
                    <Storyboard>
                        ???
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Style.Triggers>
    </Style>
</ComboBox.Style>

另一个选项是 System.Windows.Interactivity 但这在 WpfCore 3.1 中不可用

标签: c#wpfxaml.net-core-3.1

解决方案


你有几个不错的选择。
由于最后一个使用 a 的解决方案DataTrigger是最灵活的,因为它允许触发 的某些状态ComboBox.SelectedItem,我建议实施它来解决您的问题。它也是一个仅限 XAML 的解决方案,不需要像LanguageChanged.

为触发器属性设置动画

为了像 一样为属性设置动画LanguageChanged,该属性必须是 a DependencyProperty。因此,第一个示例实现LanguageChangedDependencyPropertyof MainWindow

主窗口.xaml.cs

partial class MainWindow : Window
{
  public static readonly DependencyProperty LanguageChangedProperty = DependencyProperty.Register(
    "LanguageChanged",
    typeof(bool),
    typeof(MainWindow),
    new PropertyMetadata(default(bool)));

  public bool LanguageChanged
  {
    get => (bool) GetValue(MainWindow.LanguageChangedProperty);
    set => SetValue(MainWindow.LanguageChangedProperty, value);
  }
}

主窗口.xaml

<Window x:Name="Window">
  <StackPanel>

    <TextBlock Text="Invisible"
               Visibility="{Binding RelativeSource={RelativeSource AncestorType=MainWindow}, Path=LanguageChanged, Converter={StaticResource BooleanToVisibilityConverter}}" />

    <ComboBox>
      <ComboBox.Triggers>
        <EventTrigger RoutedEvent="ComboBox.SelectionChanged">
          <BeginStoryboard>
            <Storyboard>
              <BooleanAnimationUsingKeyFrames Storyboard.TargetName="Window"
                                              Storyboard.TargetProperty="LanguageChanged">
                <DiscreteBooleanKeyFrame KeyTime="0" Value="True" />
              </BooleanAnimationUsingKeyFrames>
            </Storyboard>
          </BeginStoryboard>
        </EventTrigger>
      </ComboBox.Triggers>
    </ComboBox>
  </StackPanel>
</Window>

直接为目标控件设置动画

如果您希望切换其可见性的控件与触发控件在同一范围内,您可以Visibility直接设置动画:

主窗口.xaml

<Window x:Name="Window">
  <StackPanel>

    <TextBlock x:Name="InvisibleTextBlock"
               Text="Invisible"
               Visibility="Hidden" />

    <ComboBox>
      <ComboBox.Triggers>
        <EventTrigger RoutedEvent="ComboBox.SelectionChanged">
          <BeginStoryboard>
            <Storyboard>
              <ObjectAnimationUsingKeyFrames Storyboard.TargetName="InvisibleTextBlock"
                                             Storyboard.TargetProperty="Visibility">
                <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}" />
              </BooleanAnimationUsingKeyFrames>
            </Storyboard>
          </BeginStoryboard>
        </EventTrigger>
      </ComboBox.Triggers>
    </ComboBox>
  </StackPanel>
</Window>

实现 IValueConverter

如果您希望向触发器添加更多条件,例如选择了哪个值,您应该绑定TextBlock.VisibilitytoComboBox.SelectedItem并使用 aIValueConverter来决定是返回Visibility.Visible还是Visibilty.Hidden基于当前选定的项目:

主窗口.xaml

<Window x:Name="Window">
  <Window.Resources>

    <!-- TODO::Implement IValueConverter -->
    <SelectedItemToVisibilityConverter x:Key="SelectedItemToVisibilityConverter" />
  </Window.Resources>

  <StackPanel>

    <TextBlock Text="Invisible"
               Visibility="{Binding ElementName=LanguageSelector, Path=SelectedItem, Converter={StaticResource SelectedItemToVisibilityConverter}}" />

    <ComboBox x:Name="LanguageSelector" />
  </StackPanel>
</Window>

在 TextBlock 上实现 DataTrigger

如果您希望向触发器添加更多条件,例如选择了哪个值,您还DataTrigger可以TetxtBlockComboBox.SelectedItem. 然后,您必须将SelectedItem转换为底层ComboBox项目的实际类型,以便在绑定路径中引用项目的属性。
以下示例将 转换SelectedItem为虚构类型LanguageItem以访问LanguageItem.LanguageName属性,以触发特定的选定语言:

主窗口.xaml

<Window x:Name="Window">
  <StackPanel>

    <TextBlock x:Name="InvisibleTextBlock" Text="Invisible">
      <TextBlock.Style>
        <Style TargetType="TextBlock">
          <Setter Property="Visibility" Value="Hidden"/>
          <Style.Triggers>
            <DataTrigger Binding="{Binding ElementName=LanguageSelector, Path=SelectedItem.(LanguageItem.LanguageName)}" 
                         Value="English">
              <Setter Property="Visibility" Value="Visible"/>
            </DataTrigger>
          </Style.Triggers>
        </Style>
      </TextBlock.Style>
    </TextBlock>

    <ComboBox x:Name="LanguageSelector" />
  </StackPanel>
</Window>

推荐阅读