【问题标题】:WPF Expander ignoring data binding after user interactionWPF Expander 在用户交互后忽略数据绑定
【发布时间】:2018-08-30 13:58:25
【问题描述】:

我有一个带有扩展器的 WPF 应用程序,我希望在其中更改 IsExpanded 属性 基于我的视图模型中的枚举值,即我希望扩展器根据 这个枚举属性。我在 xaml 中使用数据触发器来更新基于 IsExpanded 的属性 关于我的枚举支持属性的值。

<Expander Header="Information and Procedures"
                              BorderThickness="0"
                              Margin="5">
                        <Expander.Style>
                            <Style TargetType="{x:Type Expander}" BasedOn="{StaticResource MetroExpander}">
                                <Style.Triggers>
                                    <DataTrigger Binding="{Binding DataContext.Item.Match, RelativeSource={RelativeSource AncestorType={x:Type UserControl}, Mode=FindAncestor}, Mode=TwoWay}" 
                                                 Value="{x:Static enum:Match.Multiple}">
                                        <Setter Property="IsExpanded" Value="False"/>
                                    </DataTrigger>
                                    <DataTrigger Binding="{Binding DataContext.Item.Match, RelativeSource={RelativeSource AncestorType={x:Type UserControl}, Mode=FindAncestor}, Mode=TwoWay}" 
                                                 Value="{x:Static enum:Match.None}">
                                        <Setter Property="IsExpanded" Value="True"/>
                                    </DataTrigger>
                                    <DataTrigger Binding="{Binding DataContext.Item.Match, RelativeSource={RelativeSource AncestorType={x:Type UserControl}, Mode=FindAncestor}, Mode=TwoWay}" 
                                                 Value="{x:Static enum:Match.Exact}">
                                        <Setter Property="IsExpanded" Value="True"/>
                                    </DataTrigger>
                                </Style.Triggers>
                            </Style>
                        </Expander.Style>
                        <WrapPanel Orientation="Horizontal" Background="Transparent">
                            <view:InformationView Margin="0 0 20 0"/>
                            <view:ProceduresView Margin="0 0 0 0" />
                        </WrapPanel>
                     </Expander>

在我们手动展开扩展器之前,这似乎有效。在此之后,似乎数据 触发器现在被忽略,手动设置的 IsExpanded 属性在用户之前不会改变 再次手动打开或关闭扩展器。

我希望用户能够手动展开或关闭它,但我希望数据触发器优先 超过用户输入。

注意:我不希望 IsExpanded 属性更改 Match 的值。 Match是单独更新的,但是它的值会影响IsExpanded

【问题讨论】:

    标签: c# wpf xaml


    【解决方案1】:

    这是因为绑定在DataTrigger,而不是IsExpanded 属性上,所以更改IsExpandedDataTrigger 绑定属性无效。

    绑定到IsExpanded 属性并使用自定义IValueConverter 在源枚举和扩展器布尔之间双向转换。

    见:https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.data.ivalueconverter

    作为一个很好的副作用,您最终还会得到更短、更易于阅读的 XAML。

    更新

    要实现所需的行为,请在视图模型上为展开状态设置一个布尔属性,该属性与ExpanderIsExpanded 属性双向绑定,并在Match 属性时在视图模型中更改它变化。这样用户和视图模型都可以修改Expander 的状态。

    类似:

    public bool IsExpanded
    {
        get => _isExpanded;
        set
        {
            _isExpanded = value;
            OnPropertyChanged(nameof(IsExpanded));
        }
    }
    
    public Match Match
    {
        get => _match;
        set
        {
           _match = value;
           switch (value)
           {
               case Exact:
               case None:
                   IsExpanded = true;
                   break;
               case Multiple:
                   IsExpanded = false;
                   break;
           }
        }
    }
    

    【讨论】:

    • 我们不希望 IsExpanded 属性更改 Match 的值。匹配单独更新,但其值会影响 IsExpanded
    • Match 的哪些值允许用户手动打开/关闭Expander
    • 如果 Match 的值表示已扩展或未扩展,则似乎没有任何空间供用户进行非覆盖选择。
    • 或者您的意思是Match 中的更改 会覆盖当前状态,但随后用户可以修改Match 更改之间的状态?
    • 用户应该始终能够展开或关闭扩展器,但无论何时 Match 的值发生变化,扩展器都应更改为正确的状态:None 和 Exact 应将 IsExpanded 设置为 true,并且 None 设置它是假的
    【解决方案2】:

    视图模型不应依赖于视图。也就是说,您不应该像 Scroog 的回答所建议的那样添加 IsExpanded 属性。

    我通过一个 Behavior 类解决了一个非常相似的问题,该类根据 Expander 的 IsEnabled 属性更改 IsExpanded。所以这仅在视图中实现。 以下类只是一个示例,可以通过添加一个绑定到将要使用的视图模型的任何属性而不是检查 IsEnabled 的依赖属性来增强。

    public class AutoExpandBehaviour 
    {
        public static readonly DependencyProperty AutoExpandProperty =
                DependencyProperty.RegisterAttached(
                "AutoExpand",
                typeof(bool),
                typeof(AutoExpandBehaviour),
                new UIPropertyMetadata(false, AutoExpandChanged));
    
        public static bool GetAutoExpand(Expander expander)
        {
            return (bool)expander.GetValue(AutoExpandProperty);
        }
    
        public static void SetAutoExpand(Expander expander, bool value)
        {
            expander.SetValue(AutoExpandProperty, value);
        }
    
        static void AutoExpandChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
        {
            var expander = depObj as Expander;
            if (expander == null)
            {
                return;
            }
    
            if (e.NewValue is bool == false)
                return;
    
            if ((bool)e.NewValue)
            {
                expander.IsEnabledChanged += Item_IsEnabledChanged;
            }
            else
            {
                expander.IsEnabledChanged -= Item_IsEnabledChanged;
            }
        }
    
        private static void Item_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            var expander = sender as Expander;
            if (expander != null)
            {
                expander.IsExpanded = (bool)e.NewValue;
            }
        }
    }
    

    在 XAML 中用作

            <Expander IsEnabled="{Binding IsFunctionAvailable}" 
                  local:AutoExpandBehaviour.AutoExpand="True"
                  ... >
                ...
            </Expander>
    

    【讨论】:

      猜你喜欢
      • 2019-12-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多