5

itemssource と selecteditem にバインドされたコンボボックスで奇妙なエラーをデバッグしようとしています。それは私を夢中にさせています。

コンボボックスが存在する選択されたタブ項目を変更すると、問題が発生します。(実際には、ComboBox の DataContext を変更する場合のみです)。SelectedItem バインディングには、値が null の場合にエラーを与えるカスタム検証ルールがあります。

問題は、wpf がタブ項目(DataContext) を切り替えるときにカスタム ルールを呼び出し、selecteditem-source が決して null ではないにもかかわらず、null の値を検証しようとすることです。これは問題です。

これは、同じエラーを示す単純化されたケースです。

NotNullValidationRule.Validateにブレークポイントを設定し、どのビュー モデル インスタンスにも存在しない場合でも、WPF が SelectedItem を null として検証しようとする方法を確認します。

アップデート

さらに実験を重ねた結果、TabControl は実際には無関係であることがわかりました。単純な ComboBox と DataContext を切り替えるボタンを使用しても、まったく同じ問題が発生します。コード例を新しいバージョンに置き換えています。

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;

namespace ComboBoxValidationBugTest
{
  public partial class MainWindow : Window
  {
    private Test t1, t2;

    public MainWindow()
    {
      InitializeComponent();

      t1 = new Test();
      t1.Items.Add("A");
      t1.Items.Add("B");
      t1.Items.Add("C");
      t1.SelectedItem = "A";

      t2 = new Test();
      t2.Items.Add("B");
      t2.Items.Add("C");
      t2.Items.Add("D");
      t2.SelectedItem = "B";

      ComboBox1.DataContext = t1;
    }

    private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
    {
      ComboBox1.DataContext = ComboBox1.DataContext == t1 ? t2 : t1;
    }
  }

  public class Test : INotifyPropertyChanged
  {
    private string _selectedItem;

    private ObservableCollection<string> _items = new ObservableCollection<string>();

    public ObservableCollection<string> Items
    {
      get
      {
        return _items;
      }
    }

    public string SelectedItem
    {
      get
      {
        return _selectedItem;
      }
      set
      {
        _selectedItem = value;
        OnPropertyChanged("SelectedItem");
      }
    }

    public override string ToString()
    {
      return _selectedItem;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
      PropertyChangedEventHandler handler = PropertyChanged;
      if (handler != null)
      {
        handler(this, new PropertyChangedEventArgs(propertyName));
      }
    }
  }

  public class NotNullValidationRule : ValidationRule
  {
    public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
    {
      if (value == null)
      {
        return new ValidationResult(false, "Value was null");
      }

      return new ValidationResult(true, null);
    }
  }
}

そしてXAML:

<Window x:Class="ComboBoxValidationBugTest.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:comboBoxValidationBugTest="clr-namespace:ComboBoxValidationBugTest"
            Title="MainWindow" Height="350" Width="525">
      <Grid>
        <DockPanel>
          <Button Content="Toggle DataContext" DockPanel.Dock="Top" Click="ButtonBase_OnClick" />
          <ComboBox ItemsSource="{Binding Items}" VerticalAlignment="Top" x:Name="ComboBox1">
            <ComboBox.SelectedItem>
              <Binding Path="SelectedItem">
                <Binding.ValidationRules>
                  <comboBoxValidationBugTest:NotNullValidationRule />
                </Binding.ValidationRules>
              </Binding>
            </ComboBox.SelectedItem>
          </ComboBox>
        </DockPanel>
      </Grid>
    </Window>
4

3 に答える 3

1

岡井さん、comboBox には多くのバグがありましたが、順序が重要であることがわかりました。これを試して:

    <ComboBox  
    SelectedValue="{Binding Aldersgrense, NotifyOnValidationError=true, ValidatesOnExceptions=true, UpdateSourceTrigger=PropertyChanged}" 
    ItemsSource="{Binding ElementName=UserControl, Path=DataContext.AldersgrenseTyper, Mode=OneTime}"
    DisplayMemberPath="Beskrivelse" SelectedValuePath="Verdi"
    Style="{StaticResource ErrorStyle}"></ComboBox>

x:Name=UserControl を設定します。SelectedItem、SelectedValue と ItemSource の順序、Items の Mode!=OneTime、およびバインディング自体の使用を使用して、いくつかのバグが導入されます。これが誰かを助けることを願っています。

于 2015-03-04T08:48:18.783 に答える
0

どうやら、新しい DataContext が設定されたときにバインディングが更新される順序に問題があるようです。ItemsSource バインディングが新しい DataContext を取得すると、(場合によっては) 選択された項目が新しいリストに存在しないことに気付き、SelectedItem を null に設定し、これを検証します。次に、SelectedItem バインディングは ItemsSource と同じ DataContext を取得し、正しい値に更新されますが、以前に失敗したルールをクリアするための検証は行われません。

バインディングの順序を変更した瞬間、うまくいきました!(つまり、xamlで)

于 2013-09-18T11:24:35.510 に答える