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