C# WPF扩展器在用户交互后忽略数据绑定

C# WPF扩展器在用户交互后忽略数据绑定,c#,wpf,xaml,C#,Wpf,Xaml,我有一个带有扩展器的WPF应用程序,我想在其中更改IsExpanded属性 基于我的视图模型中的枚举值,即我希望扩展器根据 此枚举属性无效。我在xaml中使用数据触发器来更新IsExpanded属性 关于我的枚举支持属性的值 <Expander Header="Information and Procedures" BorderThickness="0" Margin="

我有一个带有扩展器的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

这是因为绑定在
DataTrigger
上,而不是
IsExpanded
属性上,因此更改
IsExpanded
不会影响
DataTrigger
绑定属性

<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
属性,并使用自定义
IValueConverter
在源枚举和扩展器布尔之间进行双向转换

见:

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

更新

要实现所需的行为,请在viewmodel上为展开状态设置一个布尔属性,该属性双向绑定到
Expander
IsExpanded
属性,并在
Match
属性更改时在viewmodel中更改它。这样,用户和viewmodel都可以修改
扩展器的状态

比如:

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;
       }
    }
}

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

我通过一个行为类解决了一个非常类似的问题,该行为类根据扩展器的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>

...

我们不希望IsExpanded属性更改Match的值。Match单独更新,但其值会影响ISExpanded,其中
Match
的值允许用户手动打开/关闭
扩展器
?如果
Match
的值表示已展开或未展开,似乎没有任何空间供用户进行非重写选择。或者您的意思是,
Match
中的更改会重写当前状态,但用户可以修改
Match
更改之间的状态?用户应该始终能够展开或关闭扩展器,但是只要Match的值发生更改,扩展器应更改为正确的状态:None和Exact应将IsExpanded设置为true,None将其设置为false