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

如何在MVVM中禁用通过ObjectProvider Enum WPF C#提供的ComboBoxItem?,c#,wpf,xaml,mvvm,enums,C#,Wpf,Xaml,Mvvm,Enums,我有一个填充组合框的“发票操作”枚举,但我想基于ViewModel中的“CanDisplayDetails”属性禁用其中一个枚举成员(“视图”) 我不太清楚如何将IsEnabled属性绑定到ComboBoxItem ItemContainerStyle中的“CanDisplayDetails”,因为上下文似乎是枚举而不是我的ViewModel。如何更正绑定,使其能够提供枚举值,但iEnabled绑定到我的ViewModel属性?它还需要只影响“视图”ComboBoxItem。谢谢 迄今为止的风格

我有一个填充组合框的“发票操作”枚举,但我想基于ViewModel中的“CanDisplayDetails”属性禁用其中一个枚举成员(“视图”)

我不太清楚如何将IsEnabled属性绑定到ComboBoxItem ItemContainerStyle中的“CanDisplayDetails”,因为上下文似乎是枚举而不是我的ViewModel。如何更正绑定,使其能够提供枚举值,但iEnabled绑定到我的ViewModel属性?它还需要只影响“视图”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;
    }
}
public class IsViewItemConverter : IMultiValueConverter
{
    /// <summary>
    /// COnverter checks CanDisplayDetails and if ComboBoxItem is View Details, will disable if false and is View Details
    /// </summary>
    /// <param name="values">object array</param>
    /// <param name="targetType"></param>
    /// <param name="parameter"></param>
    /// <param name="culture"></param>
    /// <returns>true if should enabled item</returns>
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        bool? b = values[0] as bool?;
        ComboBoxItem c = values[1] as ComboBoxItem;
        InvoiceActionsLong? item = c.Content as InvoiceActionsLong?;

        if (b == false && (InvoiceActionsLong)item == InvoiceActionsLong.View)
        {
            return false;
        }
        else
        {
            return true;
        }
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}
公共类EnumDescriptionConverter:IValueConverter
{
/// 
///获取枚举描述
/// 
/// 
/// 
私有字符串GetEnumDescription(枚举enumObj)
{
FieldInfo FieldInfo=enumObj.GetType().GetField(enumObj.ToString());
object[]attribArray=fieldInfo.GetCustomAttributes(false);
if(attribArray.Length==0)
{
返回enumObj.ToString();
}
其他的
{
DescriptionAttribute attrib=attribArray[0]作为DescriptionAttribute;
返回属性描述;
}
}
/// 
///返回枚举成员的描述
/// 
/// 
/// 
/// 
/// 
/// 
对象IValueConverter.Convert(对象值、类型targetType、对象参数、CultureInfo区域性)
{
枚举myEnum=(枚举)值;
字符串描述=GetEnumDescription(myEnum);
返回说明;
}
对象IValueConverter.ConvertBack(对象值、类型targetType、对象参数、CultureInfo区域性)
{
返回字符串。空;
}
}
枚举:

/// <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
}
//
///枚举列出发票级别上详细信息类型(即活动、计划)的“操作”组合框的所有可用操作
/// 
公共枚举InvoiceActionsLong
{
[说明(“联系人”)]
联络,
[说明(“交付”)]
传送
[说明(“文件”)]
文件,
[说明(“注释”)]
注意,
[说明(“付款”)]
付款,
[说明(“打印”)]
印刷品,
[说明(“过程”)]
过程
[说明(“重新加载”)]
重新加载
[说明(“发送”)]
送,
[说明(“视图”)]
看法
}
my 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;
    }
}
//
///Bool表示是否可以显示详细信息
/// 
私人bool Candisplay详细信息
{
得到
{
布尔b=真;
如果(SelectedItem!=null)
{
如果(SelectedItem.AdjustmentTypeID==1)
{
b=假;
}
}
返回b;
}
}

您的
样式
绑定使用的数据上下文是
ComboboxItem
的数据上下文(这将是enum元素本身),而不是您希望的视图模型

尝试在绑定上使用相对源,沿着逻辑树向上走,获取
组合框
的数据上下文,而不是
组合框项

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

您可以通过检查VisualStudio输出窗口自行诊断此问题。您将看到一个绑定错误,它告诉您:

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

编辑

为使此仅适用于您的代码>视图< /代码>项目考虑;
  • 仅应用此样式的自定义是
    ComboBoxItem
    的内容是
    视图
    。将
    组合框.ItemContainerStyleSelector
    属性设置为选择器的实例
  • 绑定到
    CanDisplayDetails
    和枚举值的实现。如果值不是
    视图
    ,此转换器将始终返回true

为什么会发生这种情况?


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

使用@Gusdor的帮助,我终于解决了这个问题。我需要使用多绑定和多转换器,如下所示。基本上,我将ViewModel属性“CanDisplayDetails”布尔值和ComboBoxItem本身传递给MultiConverter。如果传递的布尔值为false,它将检查ComboBoxItem的内容是否为我的“查看”枚举值。如果两者都存在,则返回false,禁用ComboBoxItem。否则,它只返回true,保持所有其他项处于启用状态。感谢@Gusdor的持续帮助,并为我指出了正确的SO讨论!希望这将有助于其他人在未来

已编辑的组合框项ContainerStyle:

<ComboBox.ItemContainerStyle>
                <Style TargetType="{x:Type ComboBoxItem}">
                    <Setter Property="IsEnabled">
                        <Setter.Value>
                            <MultiBinding Converter="{StaticResource IsViewItemConverter}">
                                <Binding Path="DataContext.CanDisplayDetails" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}" />
                                <Binding RelativeSource="{RelativeSource Self}"/>
                            </MultiBinding>
                        </Setter.Value>
                    </Setter>
                </Style>
            </ComboBox.ItemContainerStyle>

取代IValueConverter的新多转换器:

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;
    }
}
public class IsViewItemConverter : IMultiValueConverter
{
    /// <summary>
    /// COnverter checks CanDisplayDetails and if ComboBoxItem is View Details, will disable if false and is View Details
    /// </summary>
    /// <param name="values">object array</param>
    /// <param name="targetType"></param>
    /// <param name="parameter"></param>
    /// <param name="culture"></param>
    /// <returns>true if should enabled item</returns>
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        bool? b = values[0] as bool?;
        ComboBoxItem c = values[1] as ComboBoxItem;
        InvoiceActionsLong? item = c.Content as InvoiceActionsLong?;

        if (b == false && (InvoiceActionsLong)item == InvoiceActionsLong.View)
        {
            return false;
        }
        else
        {
            return true;
        }
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}
public类IsViewItemConverter:IMultiValueConverter
{
/// 
///转换器会检查CanDisplayDetails,如果ComboBoxItem是View Details,则会禁用,如果为false,则为View Details
/// 
///对象数组
/// 
/// 
/// 
///如果应启用项目,则为true
公共对象转换(对象[]值,类型targetType,对象参数,CultureInfo区域性)
{
bool?b=值[0]为bool?;
ComboBoxItem c=值[1]作为ComboxItem;
InvoiceActionsLong?项目=c。内容为InvoiceActionsLong?;
如果(b==false&(InvoiceActionsLong)项=