7

しばらくの間 WPF を使用していましたが、助けが必要です。

以下のComboBoxようなものがあります:

<TabControl>
    <TabItem Header="1">
        <ComboBox ItemsSource="{Binding MyList}" SelectedItem="{Binding MyListSelection}"/>
    </TabItem>
    <TabItem Header="2"/>
</TabControl>

タブ1から離れてから戻ってくると、選択が削除されます。その理由は、コントロールが範囲外に出てから戻ったときに破棄されるためだと思います。しかし、その過程で SelectedItem が null になり、これは実際にはユーザーが望んでいたものではなく、UI によるイベントです。ライフサイクル。

では、どのルートを選ぶのがベストなのだろうか?私は MVVM でこのアプリを構築しているので、ViewModel の MyListSelection プロパティの set 呼び出しを無視できますが、あちこちに ComboBox があり、WPF のバグと見なされるもののために ViewModel を変更するのは好きではありません。

WPF ComboBox をサブクラス化できますが、SelectedItemChanging イベントがなく、SelectedItem が変更されたときにのみハンドラーを追加できます。

何か案は?

アップデート:

さて、壁に頭をぶつけた後、問題が再現されなかった理由がわかりました。リスト項目の型が何らかの理由でクラスの場合、SelectedItem は WPF によって null に設定されますが、値の型の場合は設定されません。

これが私のテストクラスです(VMBaseはINotifyPropertyChangedを実装する単なる抽象クラスです):

public class TestListViewModel : VMBase
{
    public TestListViewModel()
    {
        TestList = new List<TestViewModel>();
        for (int i = 0; i < 10; i++)
        {
            TestList.Add(new TestViewModel(i.ToString()));
        }
    }

    public List<TestViewModel> TestList { get; set; }

    TestViewModel _SelectedTest;
    public TestViewModel SelectedTest
    {
        get { return _SelectedTest; }
        set
        {
            _SelectedTest = value;
            OnPropertyChanged("SelectedTest");
        }
    }
}

public class TestViewModel : VMBase
{
  public string Name {get;set;}
}

したがって、TestList を int 型に変更してタブ間を行き来しても、SelectedItem は同じままです。ただし、タイプTestViewModelSelectedTest の場合、タブ項目がフォーカスから外れると null に設定されます。

どうしたの?

4

7 に答える 7

10

私はまったく同じ問題を抱えていましたが、今まで問題が何であるかを理解できませんでした。同じOS、.Netバージョン、ハードウェア仕様の4つの異なるマシンでテストしたところ、そのうちの2つで問題を再現できましたが、他のマシンでは問題なく動作しました。私がうまくいくことがわかった回避策は、ItemsSourceの前にSelectedItemバインディングを定義することです。不思議なことに、このパターンに従うと、すべてが期待どおりに機能します。そうは言っても、次のことを行う必要があります。

<Window x:Class="ComboBoxInTabItemSpike.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <StackPanel>
        <TabControl>
            <TabItem Header="1">
                <ComboBox SelectedItem="{Binding MySelect}" ItemsSource="{Binding MyList}"/>
            </TabItem>
            <TabItem Header="2"/>
        </TabControl>
        <TextBlock Text="{Binding MySelect}"/>
    </StackPanel>
</Window>
于 2010-05-07T14:51:39.010 に答える
0

バインディングを確認することをお勧めします。アプリ内の他の何かが選択したアイテムまたはアイテムソースを変更している場合、バインディングは壊れます。Visual Studioの出力ウィンドウで、エラーがあるかどうかを確認することもできます。

于 2010-01-28T18:28:01.710 に答える
0

コンボボックスによるこの動作は、実際よりも優れた方法でコンパイラによって実装される必要があります... IE コンパイラは、ItemsSource の型と、SelectedItem がバインドされているプロパティの型参照値をチェックして確認する必要があります。比較可能な値を返すことはありません

Equals() および GetHashCode() メソッドをオーバーライドすることを検討する可能性があることを警告する必要があります...

今日はこれに多くの時間を無駄にしました!!

于 2011-07-25T20:34:14.853 に答える
0

ここで見逃しているのは、SelectedItem の TwoWay バインディングだと思います。MyList(bound ItemsSource) と MyListSelection(ケース内の SelectedItem への結合) を含む ViewModel クラスをバインドすると、別のタブに移動しても常にこれらの情報が保持されます。したがって、このタブに戻ると、MyListSelection が再び ComboBoc.SelectedItem にバインドされ、問題がなくなります。これを試して、私に知らせてください。

于 2010-01-28T20:05:27.063 に答える
0

リスト内の参照型でまったく同じ問題が発生していました。解決策は、TestViewModel で Equals() をオーバーライドして、WPF がオブジェクト間で (参照チェックではなく) 値の等価性チェックを実行して、どれが SelectedItem であるかを判断できるようにすることでした。たまたま、TestViewModel の識別機能である ID フィールドがありました。

于 2010-11-10T22:55:57.947 に答える
0

OPの変更後に編集されました。こんにちは、ホセ、あなたが言及したエラーを再現できません。したがって、コントロールが破壊されているというあなたの仮定は間違っています。コンボボックスは、現在参照型を使用している場合でも、以下のコード ビハインドで期待どおりに動作します。TabItems を変更するときは、コードの他の部分を開始する必要があります。

<Window x:Class="ComboBoxInTabItemSpike.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <StackPanel>
        <TabControl>
            <TabItem Header="1">
                <ComboBox ItemsSource="{Binding MyList}"
                          SelectedItem="{Binding MySelect}"/>
            </TabItem>
            <TabItem Header="2"/>
        </TabControl>
        <TextBlock Text="{Binding MySelect}"/>
    </StackPanel>
</Window>

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

namespace ComboBoxInTabItemSpike
{
    public partial class Window1 : Window, INotifyPropertyChanged
    {
        public Window1()
        {
            InitializeComponent();
            MyList=new ObservableCollection<TestObject>(
                new[]{new TestObject("1"),new TestObject("2"),new TestObject("3") });
            DataContext = this;
        }

        public ObservableCollection<TestObject> MyList { get; set; }

        private TestObject mySelect;
        public TestObject MySelect
        {
            get { return mySelect; }
            set{ mySelect = value;
            if(PropertyChanged!=null)
                PropertyChanged(this,new PropertyChangedEventArgs("MySelect"));} 
        }

        public TestObject MySelectedItem
        {
            get { return (TestObject)GetValue(MySelectedItemProperty); }
            set { SetValue(MySelectedItemProperty, value); }
        }

        public static readonly DependencyProperty MySelectedItemProperty =
            DependencyProperty.Register("MySelectedItem",
                                typeof(TestObject),
                                typeof(Window1),
                                new UIPropertyMetadata(null));

        public event PropertyChangedEventHandler PropertyChanged;
    }

    public class TestObject
    {
        public string Name { get; set; }

        public TestObject(string name)
        {
            Name = name;
        }

        public override string ToString()
        {
            return Name;
        }
    }
}
于 2010-01-28T18:16:23.430 に答える
0

これは単純な null チェックで解決できると思います。

public TestViewModel SelectedTest
{
    get { return _SelectedTest; }
    set
    {
        if(value != null)
            _SelectedTest = value;
        OnPropertyChanged("SelectedTest");
    }
}

これは、ComboBox がリサイクル時に SelectedIndex をリセットする傾向があるためです。この単純な null チェックにより、最後の有効なアイテムに強制的に再バインドされます。

于 2010-01-29T05:52:12.837 に答える