c# - 如何在 MVVM 中禁用通过 ObjectProvider Enum WPF C# 提供的 ComboBoxItem?

标签 c# wpf xaml mvvm enums

我有一个填充组合框的“发票操作”枚举,但我想根据 ViewModel 中的“CanDisplayDetails”属性禁用枚举成员之一(“View”)。

我不太清楚如何将 IsEnabled 属性绑定(bind)到 ComboBoxItem ItemContainerStyle 中的“CanDisplayDetails”,因为上下文似乎是 Enum 而不是我的 ViewModel。如何更正绑定(bind),以便它可以提供枚举值,但 IsEnabled 绑定(bind)到我的 ViewModel 属性?而且它还需要只影响“View”ComboBoxItem。谢谢!

到目前为止的风格想法:

<ComboBox.ItemContainerStyle>
    <Style TargetType="{x:Type ComboBoxItem}">
        <Setter Property="IsEnabled" Value="{Binding CanDisplayDetails}"/>
    </Style>
</ComboBox.ItemContainerStyle>

在 XAML UserControl 的资源中:

<ObjectDataProvider x:Key="ActionsEnum" MethodName="GetValues" ObjectType="{x:Type sys:Enum}">
        <ObjectDataProvider.MethodParameters>
            <x:TypeExtension TypeName="Constants:InvoiceActionsLong"/>
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>

同一用户控件中的组合框:

<ComboBox Grid.Column="1" ItemsSource="{Binding Source={StaticResource ActionsEnum}}" IsEnabled="{Binding SelectedItem, Converter={StaticResource SelectionConverter}}"
                      SelectedItem="{Binding SelectedAction}">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Converter={StaticResource EnumDescriptionConverter}}" />
        </DataTemplate>
    </ComboBox.ItemTemplate>
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="SelectionChanged">
            <i:InvokeCommandAction Command="{Binding ActionCommand}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</ComboBox>

EnumDescriptionConverter:

public class EnumDescriptionConverter : IValueConverter
{
    /// <summary>
    /// Get enum description
    /// </summary>
    /// <param name="enumObj"></param>
    /// <returns></returns>
    private string GetEnumDescription(Enum enumObj)
    {
        FieldInfo fieldInfo = enumObj.GetType().GetField(enumObj.ToString());

        object[] attribArray = fieldInfo.GetCustomAttributes(false);

        if (attribArray.Length == 0)
        {
            return enumObj.ToString();
        }
        else
        {
            DescriptionAttribute attrib = attribArray[0] as DescriptionAttribute;
            return attrib.Description;
        }
    }

    /// <summary>
    /// Returns an enum member's description
    /// </summary>
    /// <param name="value"></param>
    /// <param name="targetType"></param>
    /// <param name="parameter"></param>
    /// <param name="culture"></param>
    /// <returns></returns>
    object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        Enum myEnum = (Enum)value;
        string description = GetEnumDescription(myEnum);
        return description;
    }

    object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return string.Empty;
    }
}

枚举:

/// <summary>
/// Enum lists all available Actions for Action Combo Box at the Invoice level for DETAIL types ie. active, plan
/// </summary>
public enum InvoiceActionsLong
{
    [Description("Contacts")]
    Contacts,
    [Description("Delivery")]
    Delivery,
    [Description("Documents")]
    Documents,
    [Description("Note")]
    Note,
    [Description("Payments")]
    Payments,
    [Description("Print")]
    Print,
    [Description("Process")]
    Process,
    [Description("Reload")]
    Reload,
    [Description("Send")]
    Send,
    [Description("View")]
    View
}

我的 ViewModel 中的属性:

/// <summary>
/// Bool denotes whether can display details
/// </summary>
private bool CanDisplayDetails
{
    get
    {
        bool b = true;

        if (SelectedItem != null)
        {
            if (SelectedItem.AdjustmentTypeID == 1)
            {
                b = false;
            }
        }

        return b;
    }
}

最佳答案

您的 Style 绑定(bind)使用的数据上下文是 ComboboxItem 的数据上下文(这将是枚举元素本身),而不是 View 模型,就像您一样希望。

尝试在绑定(bind)上使用相对源来遍历逻辑树并获取 ComboBox 的数据上下文,而不是 ComboBoxItem

<Setter Property="IsEnabled" Value="{Binding DataContext.CanDisplayDetails, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}}"/>

您可以通过检查 Visual Studio 输出窗口自行诊断。您将看到一个绑定(bind)错误,告诉您类似的内容;

数据错误:在 _InvoiceActionsLong_ 实例上找不到 CanDisplayDetails 属性

编辑

为了使其仅适用于您的View项目,请考虑;

  • 自定义StyleSelector仅应用此样式的 ComboBoxItem 的内容是 View。将 ComboBox.ItemContainerStyleSelector 属性设置为选择器的实例。
  • 一个IMultiValueConverter绑定(bind)到 CanDisplayDetails 和枚举值的实现。如果值不是 View,此转换器将始终返回 true。

为什么会发生这种情况?

生成的 ItemSelector 项(例如 ComboBoxItem)的数据上下文会自动设置为该项表示的数据。

关于c# - 如何在 MVVM 中禁用通过 ObjectProvider Enum WPF C# 提供的 ComboBoxItem?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22379227/

相关文章:

c# - 适用于 Citrix 的 SendKeys 替代方案

c# - 控制台应用程序更新到.Net Core 3.1错误找不到框架 'Microsoft.AspNetCore.App',版本 '3.1.0'

wpf - 带有水平项目的 ListView

wpf - 路径数据属性的M,L,XAML是什么

c# - 对象引用未设置到对象实例,在 WPF 设计器中,位于 x :Reference

c# - 在本地测试 Slack 交互式消息

c# - 使用 S.M.A.R.T 和 WMI 加载/卸载循环计数

wpf - 有没有办法注释掉包含注释的 XAML?

c# - WPF 用户控件项未显示

c# - 从枚举值列表创建可检查上下文菜单的通用方法