wpf combobox multibinding 无法在第一步中获取相对源组合框的组合框项目(以编程方式添加或绑定到数据库)

wpf combobox multibinding could not get combobox items (programmatically added or bind to database) of relative source combobox in first step

我想根据特定条件禁用某些组合框项目。对于这个问题,我使用了多重绑定。 如果我在xaml中描述了combobox的所有项目,就没有问题。但我想以编程方式填充组合框项目。所以在这种情况下,我无法获取项目,returns null,并在第一步中将我退出程序。 我的 xaml 代码是这样的:

<Window.Resources>
    <local:TekerDisabler x:Key="tekerDisabler"/>
</Window.Resources>
<Grid>
    <ComboBox x:Name="cbx" HorizontalAlignment="Left" Margin="41,125,0,0" VerticalAlignment="Top" Width="227">
        <ComboBox.ItemContainerStyle>
            <Style TargetType="ComboBoxItem">
                <Setter Property="IsEnabled">
                    <Setter.Value>
                        <MultiBinding Converter="{StaticResource tekerDisabler}">
                            <Binding ElementName="txt1" Path="Text"/>
                            <Binding ElementName="txt2" Path="Text"/>
                            <Binding ElementName="txt3" Path="Text"/>

                            <Binding RelativeSource="{RelativeSource Self}"/>
                        </MultiBinding>
                    </Setter.Value>
                </Setter>
            </Style>
        </ComboBox.ItemContainerStyle>
    </ComboBox>
    <TextBox x:Name="txt1" HorizontalAlignment="Left" Height="23" Margin="41,38,0,0" TextWrapping="Wrap"  VerticalAlignment="Top" Width="120"/>
    <TextBox x:Name="txt2" HorizontalAlignment="Left" Height="23" Margin="207,38,0,0" TextWrapping="Wrap"  VerticalAlignment="Top" Width="211" TextChanged="txt2_TextChanged"/>
    <TextBox x:Name="txt3" HorizontalAlignment="Left" Height="24" Margin="478,37,0,0" TextWrapping="Wrap"  VerticalAlignment="Top" Width="196"/>

</Grid>

我的 C# 代码是这样的:

namespace App1.Pencereler
{

public partial class deneme : Window
{
    public deneme()
    {
        InitializeComponent();
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        cbx.Items.Add("0");
        cbx.Items.Add("1");
        cbx.Items.Add("2");
        cbx.Items.Add("3");
    }

    private void txt2_TextChanged(object sender, TextChangedEventArgs e)
    {
        cbx.SelectedIndex = 1;
    }
}
class TekerDisabler : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        bool enable = true;
        var itemler = values[3] as ComboBoxItem;
        if (itemler == null || values[0].ToString() == null || values[1].ToString() == null || values[2].ToString() == null)
        { enable = true; }
        else
        {
            switch (values[0].ToString())
            {
                case "a":
                    switch (values[1].ToString())
                    {
                        case "b":
                            switch (values[2].ToString())
                            {
                                case "c":
                                    switch (itemler.Content.ToString())
                                    {
                                        case "0":
                                        case "2":
                                            enable = false;
                                            break;
                                        default:
                                            enable = true;
                                            break;
                                    }
                                    break;
                                default:
                                    enable = true;
                                    break;
                            }
                            break;
                        default:
                            enable = true;
                            break;
                    }
                    break;
                default:
                    enable = true;
                    break;
            }

        }
        return enable;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

}

例如,在第一步中,我写txt1:a、txt2:b、txt3:d等所有项目的显示启用,然后我写txt1:a, txt2:b, txt3:c 和combobox (0,2) 的内容禁用,没有问题。但是当 运行 程序时,在第一步我写 txt1:a, txt2:b, txt3:c 当下拉组合框时,程序把我赶出去了。 如何克服这个问题?

报错信息及详细信息如下:

错误详情如下:

System.NullReferenceException
  HResult=0x80004003
  İleti=Nesne başvurusu bir nesnenin örneğine ayarlanmadı.
  Kaynak=App1
  StackTrace:
   konum App1.Pencereler.TekerDisabler.Convert(Object[] values, Type targetType, Object parameter, CultureInfo culture) D:\C Sharp\WPF\App1\App1\Pencereler\deneme.xaml.cs içinde: 60. satır
   konum System.Windows.Data.MultiBindingExpression.TransferValue()
   konum System.Windows.Data.MultiBindingExpression.Transfer()
   konum System.Windows.Data.MultiBindingExpression.UpdateTarget(Boolean includeInnerBindings)
   konum System.Windows.Data.MultiBindingExpression.AttachToContext(Boolean lastChance)
   konum System.Windows.Data.MultiBindingExpression.AttachOverride(DependencyObject d, DependencyProperty dp)
   konum System.Windows.Data.BindingExpressionBase.OnAttach(DependencyObject d, DependencyProperty dp)

如果知道您得到的确切错误是什么,那将很有趣。
我假设 ComboBoxItem.Content returns null。打开 ComboBox 后,将呈现(生成)项目容器。此时只有数据项存在。因此,第一次打开下拉列表时,所有项目容器 null 即将呈现。

无论如何,您的代码的以下简化版本很可能会解决您的问题:

TekerDisabler.cs

public class TekerDisabler : IMultiValueConverter
{
  #region Implementation of IMultiValueConverter

  public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
  {
    var currentItem = values[0] as string;
    var predicate = "abc";
    string input = string.Concat(values.Skip(1).Cast<string>());
    return !(input.Equals(predicate, StringComparison.Ordinal)
             && (currentItem.Equals("0", StringComparison.Ordinal)
                 || currentItem.Equals("2", StringComparison.Ordinal)));
  }

  public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) =>
    throw new NotSupportedException();

  #endregion
}

TekerDisabler.cs - 替代版本

public class TekerDisabler : IMultiValueConverter
{
  #region Implementation of IMultiValueConverter

  public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
  {
    var currentItem = values[0] as string;
    var predicate = "abc";
    string input = string.Concat(values.Skip(1).Cast<string>());
    return !(values[1].Equals("a", StringComparison.Ordinal)
             && values[2].Equals("b", StringComparison.Ordinal)
             && values[3].Equals("c", StringComparison.Ordinal)
             && (currentItem.Equals("0", StringComparison.Ordinal)
                 || currentItem.Equals("2", StringComparison.Ordinal)));
  }

  public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) =>
    throw new NotSupportedException();

  #endregion
}

MainWindow.xamlk.cs

partial class MainWIndow : Window
{
  public static readonly DependencyProperty ItemsProperty = DependencyProperty.Register(
    "Items",
    typeof(ObservableCollection<string>),
    typeof(MainWindow),
    new PropertyMetadata(default(ObservableCollection<string>)));

  public ObservableCollection<string> Items
  {
    get => (ObservableCollection<string>) GetValue(MainWindow.ResultsProperty);
    set => SetValue(MainWindow.ResultsProperty, value);
  }
}

MainWindow.xaml

<ComboBox ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=main:MainWindow}, Path=Items}">
  <ComboBox.ItemContainerStyle>
    <Style TargetType="ComboBoxItem">
      <Setter Property="IsEnabled">
        <Setter.Value>
          <MultiBinding Converter="{StaticResource CellForegroundMultiValueConverter}">
            <Binding />
            <Binding ElementName="TextBox1" Path="Text" />
            <Binding ElementName="TextBox2" Path="Text" />
            <Binding ElementName="TextBox3" Path="Text" />
          </MultiBinding>
        </Setter.Value>
      </Setter>
    </Style>
  </ComboBox.ItemContainerStyle>
</ComboBox>
<TextBox x:Name="TextBox1" />
<TextBox x:Name="TextBox2" />
<TextBox x:Name="TextBox3" />

我通过添加

成功解决了我的问题
        cbx.IsDropDownOpen = true;
        cbx.IsDropDownOpen = false;

之后
cbx.Items.Add("0");
cbx.Items.Add("1");
cbx.Items.Add("2");
cbx.Items.Add("3");

'Window_Loaded' 事件中。