问题
I want to disable some specific items of combobox conditionally. For Example, I have two comboboxes (combobox1,combobox2), I want to disable some specific items of combobox2 (not to remove, just want to disable) according to selected item of combobox1. My xaml codes are like that:
<Grid>
<ComboBox x:Name="combobox1" HorizontalAlignment="Left" Margin="142,99,0,0" VerticalAlignment="Top" Width="319">
<ComboBoxItem>Choice1</ComboBoxItem>
<ComboBoxItem>Choice2</ComboBoxItem>
<ComboBoxItem>Choice3</ComboBoxItem>
</ComboBox>
<ComboBox x:Name="combobox2" HorizontalAlignment="Left" Margin="520,99,0,0" VerticalAlignment="Top" Width="358">
<ComboBoxItem>Selection1</ComboBoxItem>
<ComboBoxItem>Selection2</ComboBoxItem>
<ComboBoxItem>Selection3</ComboBoxItem>
<ComboBoxItem>Selection4</ComboBoxItem>
<ComboBoxItem>Selection5</ComboBoxItem>
<ComboBoxItem>Selection6</ComboBoxItem>
</ComboBox>
</Grid>
and C# codes are like that:
public partial class UC_Servis : UserControl
{
public UC_Servis()
{
InitializeComponent();
}
private void combobox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
switch (combobox1.SelectedIndex)
{
case 0:
combobox2.SelectedIndex = 0;
break;
case 1:
combobox2.SelectedIndex = 1;
break;
case 2:
combobox2.SelectedIndex = 2;
break;
default:
break;
}
combobox2.ItemContainerGenerator.StatusChanged += new EventHandler(ItemContainerGenerator_StatusChanged);
}
private void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
{
if (combobox2.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
{
foreach (var a in combobox2.Items)
{
int currentPosition = combobox2.Items.IndexOf(a);
ComboBoxItem cbi = (ComboBoxItem)combobox2.ItemContainerGenerator.ContainerFromIndex(currentPosition);
switch (combobox1.SelectedIndex)
{
case 0:
switch (a.ToString())
{
case "Selection4":
case "Selection5":
cbi.IsEnabled = false;
break;
default:
cbi.IsEnabled = true;
break;
}
break;
case 1:
switch (a.ToString())
{
case "Selection1":
case "Selection3":
cbi.IsEnabled = false;
break;
default:
cbi.IsEnabled = true;
break;
}
break;
case 2:
switch (a.ToString())
{
case "Selection2":
case "Selection6":
cbi.IsEnabled = false;
break;
default:
cbi.IsEnabled = true;
break;
}
break;
default:
break;
}
}
}
}
}
When I run, there is no change, I could not make none of the items of combobox2 disabled.
How can I do that? what's wrong?
EXTRA QUESTION
If Comboboxes have static items, I accomplished to change displaying ability of combobox items by support of neelesh bodgal. But, in my original study, comboboxes' item sources are binded to database, so items of comboboxes' items can change by situations. I tryed to adapt neelesh bodgal's codes to my original study, but all of the items are enabled. in my original study xaml codes are like that:
<Window x:Class="MyStudy.Pencereler.MamulStkConfig"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MyStudy.Pencereler"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
mc:Ignorable="d"
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextElement.FontWeight="Regular"
TextElement.FontSize="13"
TextOptions.TextFormattingMode="Ideal"
TextOptions.TextRenderingMode="Auto"
Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{DynamicResource MaterialDesignFont}"
Title="MamulStkConfig" ResizeMode="NoResize" WindowStartupLocation="CenterScreen" AllowsTransparency="True" WindowStyle="None" WindowState="Maximized" Width="1300" Height="700">
<Window.Resources>
<local:TekerDisabler x:Key="tekerDisabler"/>
</Window.Resources>
<Grid>
<ComboBox x:Name="Cbx_UrunGrubu" SelectionChanged="Cbx_UrunGrubu_SelectionChanged" materialDesign:HintAssist.Hint="ÜRÜN GRUBU" Style="{StaticResource MaterialDesignFloatingHintComboBox}" DisplayMemberPath="kodTipTanim" SelectedValuePath="kodTipId" />
<ComboBox x:Name="Cbx_Secim1" SelectionChanged="Cbx_Secim1_SelectionChanged" materialDesign:HintAssist.Hint="{Binding ElementName=txt_Hint1,Path=Text}" Style="{StaticResource MaterialDesignFloatingHintComboBox}" DisplayMemberPath="TANIM" SelectedValuePath="KOD" />
<ComboBox x:Name="Cbx_Secim2" SelectionChanged="Cbx_Secim2_SelectionChanged" materialDesign:HintAssist.Hint="{Binding ElementName=txt_Hint2,Path=Text}" Style="{StaticResource MaterialDesignFloatingHintComboBox}" DisplayMemberPath="TANIM" SelectedValuePath="KOD" />
<ComboBox x:Name="Cbx_Secim3" SelectionChanged="Cbx_Secim3_SelectionChanged" materialDesign:HintAssist.Hint="{Binding ElementName=txt_Hint3,Path=Text}" Style="{StaticResource MaterialDesignFloatingHintComboBox}" DisplayMemberPath="TANIM" SelectedValuePath="KOD" />
<ComboBox x:Name="Cbx_Ops10" SelectionChanged="Cbx_Ops10_SelectionChanged" materialDesign:HintAssist.Hint="{Binding ElementName=txt_Hint10,Path=Text}" Style="{StaticResource MaterialDesignFloatingHintComboBox}" DisplayMemberPath="TANIM" SelectedValuePath="KOD" >
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem">
<Setter Property="IsEnabled">
<Setter.Value>
<MultiBinding Converter="{StaticResource tekerDisabler}">
<Binding ElementName="Cbx_UrunGrubu" Path="SelectedItem"/>
<Binding ElementName="Cbx_Ops3" Path="SelectedItem"/>
<Binding ElementName="Cbx_Ops2" Path="SelectedItem"/>
<Binding RelativeSource="{RelativeSource Self}"/>
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
</Grid>
And MyStudy C# codes are like that:
public class TekerDisabler : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
bool enable = true;
var cbxUrunGrupSelectedItem = values[0] as ComboBoxItem;
var cbxOp3SelectedItem = values[1] as ComboBoxItem;
var cbxOp2SelectedItem = values[2] as ComboBoxItem;
var cbxOp10Item = values[3] as ComboBoxItem;
if (cbxUrunGrupSelectedItem == null || cbxOp2SelectedItem == null || cbxOp3SelectedItem == null || cbxOp10Item == null)
return true;
switch (cbxUrunGrupSelectedItem.Content.ToString())
{
case "DÖNERLİ PULLUK":
switch (cbxOp3SelectedItem.Content.ToString())
{
case "(100X100X10) Profil":
if (cbxOp10Item.Content.ToString() == "LASTİK TEKER BÜYÜK (10x80-12)") { enable = false; }
break;
case "(120X120X10) Profil":
switch (cbxOp2SelectedItem.Content.ToString())
{
case "3'LÜ (2+1)":
case "3'LÜ (3+0)":
case "3'LÜ (FLANŞSIZ)":
if (cbxOp10Item.Content.ToString() == "TEKERSİZ" || cbxOp10Item.Content.ToString() == "LASTİK TEKER BÜYÜK (10x80-12)")
{ enable = false; }
break;
case "1'Lİ (1+0)":
case "1'Lİ (FLANŞSIZ)":
case "2'Lİ (1+1)":
case "2'Lİ (2+0)":
case "2'Lİ (FLANŞSIZ)":
if (cbxOp10Item.Content.ToString() == "LASTİK TEKER BÜYÜK (10x80-12)")
{ enable = false; }
break;
default:
if (cbxOp10Item.Content.ToString() == "TEKERSİZ" || cbxOp10Item.Content.ToString() == "DEMİR TEKER" || cbxOp10Item.Content.ToString() == "LASTİK TEKER (20,5x8,00-10)")
{ enable = false; }
break;
}
break;
case "(140X140X10) Profil":
case "(140X140X14) Profil":
if (cbxOp10Item.Content.ToString() == "TEKERSİZ" || cbxOp10Item.Content.ToString() == "DEMİR TEKER" || cbxOp10Item.Content.ToString() == "LASTİK TEKER (20,5x8,00-10)")
{ enable = false; }
break;
default:
enable = true;
break;
}
break;
default:
break;
}
return enable;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
How can I overcome this problem?
回答1:
This is a another way of doing it using data binding. This is working code. You can replace this code in your project and check.
<UserControl x:Class="WpfApplication1.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<local:Disabler x:Key="disabler"/>
</UserControl.Resources>
<Grid>
<ComboBox x:Name="combobox1" HorizontalAlignment="Left" Margin="142,99,0,0"
VerticalAlignment="Top" Width="319">
<ComboBoxItem>Choice1</ComboBoxItem>
<ComboBoxItem>Choice2</ComboBoxItem>
<ComboBoxItem>Choice3</ComboBoxItem>
</ComboBox>
<ComboBox x:Name="combobox2" HorizontalAlignment="Left" Margin="520,99,0,0" VerticalAlignment="Top" Width="358">
<ComboBoxItem>Selection1</ComboBoxItem>
<ComboBoxItem>Selection2</ComboBoxItem>
<ComboBoxItem>Selection3</ComboBoxItem>
<ComboBoxItem>Selection4</ComboBoxItem>
<ComboBoxItem>Selection5</ComboBoxItem>
<ComboBoxItem>Selection6</ComboBoxItem>
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem">
<Setter Property="IsEnabled">
<Setter.Value>
<MultiBinding Converter="{StaticResource disabler}">
<!--Here you can bind the proper u want to use in -->
<!--converter to enable/ disable comboboxitem-->
<Binding ElementName="combobox1" Path="SelectedItem"/>
<!--Bind to the current comboboxitem which needs to enabled/disabled-->
<Binding RelativeSource="{RelativeSource Self}"/>
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
</Grid>
</UserControl>
Define the converter in the code behind as follows
using System;
using System.Globalization;
using System.Windows.Controls;
using System.Windows.Data;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for UserControl1.xaml
/// </summary>
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
}
class Disabler : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
bool enable = true;
var comboxbox1SelectedItem = values[0] as ComboBoxItem;
var comboxbox2Item = values[1] as ComboBoxItem;
if (comboxbox1SelectedItem == null || comboxbox2Item == null)
return true;
if (comboxbox1SelectedItem.Content.ToString() == "Choice1")
{
if(comboxbox2Item.Content.ToString() == "Selection4" || (comboxbox2Item.Content.ToString() == "Selection5")){
enable = false;
}
}
else if (comboxbox1SelectedItem.Content.ToString() == "Choice2")
{
if (comboxbox2Item.Content.ToString() == "Selection1" || (comboxbox2Item.Content.ToString() == "Selection3")){
enable = false;
}
}
else if (comboxbox1SelectedItem.Content.ToString() == "Choice3")
{
if (comboxbox2Item.Content.ToString() == "Selection2" || (comboxbox2Item.Content.ToString() == "Selection6")){
enable = false;
}
}
return enable;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
For more than one combobox deciding the enable/disable items, same example can be extended as follows
<UserControl x:Class="WpfApplication1.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<local:Disabler x:Key="disabler"/>
<local:Disabler2 x:Key="disabler2"/>
</UserControl.Resources>
<Grid>
<ComboBox x:Name="combobox1" HorizontalAlignment="Left" Margin="142,99,0,0"
VerticalAlignment="Top" Width="319">
<ComboBoxItem>Choice1</ComboBoxItem>
<ComboBoxItem>Choice2</ComboBoxItem>
<ComboBoxItem>Choice3</ComboBoxItem>
</ComboBox>
<ComboBox x:Name="combobox2" HorizontalAlignment="Left" Margin="142,99,0,0"
VerticalAlignment="Top" Width="319">
<ComboBoxItem>Choice21</ComboBoxItem>
<ComboBoxItem>Choice22</ComboBoxItem>
<ComboBoxItem>Choice23</ComboBoxItem>
</ComboBox>
<ComboBox x:Name="combobox3" HorizontalAlignment="Left" Margin="520,99,0,0" VerticalAlignment="Top" Width="358">
<ComboBoxItem>Selection1</ComboBoxItem>
<ComboBoxItem>Selection2</ComboBoxItem>
<ComboBoxItem>Selection3</ComboBoxItem>
<ComboBoxItem>Selection4</ComboBoxItem>
<ComboBoxItem>Selection5</ComboBoxItem>
<ComboBoxItem>Selection6</ComboBoxItem>
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem">
<Setter Property="IsEnabled">
<Setter.Value>
<MultiBinding Converter="{StaticResource disabler2}">
<!--Here you can bind the proper u want to use in -->
<!--converter to enable/ disable comboboxitem-->
<Binding ElementName="combobox1" Path="SelectedItem"/>
<Binding ElementName="combobox2" Path="SelectedItem"/>
<!--Bind to the current comboboxitem which needs to enabled/disabled-->
<Binding RelativeSource="{RelativeSource Self}"/>
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
</Grid>
</UserControl>
You can create a new valueconveter for processing three item as follows
class Disabler2 : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
bool enable = true;
var comboxbox1SelectedItem = values[0] as ComboBoxItem;
var comboxbox2SelectedItem = values[1] as ComboBoxItem;
var comboxbox3Item = values[2] as ComboBoxItem;
//Logic to disable items
return enable;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
来源:https://stackoverflow.com/questions/62151905/how-to-disable-specific-items-of-combobox-programmatically-by-condition-in-wpf-c