10

次の XAML を検討してください。

<ComboBox Name="CompanyComboBox" 
    HorizontalAlignment="Stretch"
    ItemsSource="{Binding Path=GlobalData.Companies}" 
    SelectedValuePath="Id"
    SelectedValue="{Binding Customer.CompanyId, ValidatesOnDataErrors=True}"
    DisplayMemberPath="Name" />

GlobalData.CompaniesIEnumerable<Company>会社のコレクション ( ) です。このコレクションはバックグラウンドで再ロードできます (Web サービスからダウンロードされます)。これが発生すると、ComboBox はバインディングを介してアイテムを正しくリロードします。ただし、副作用として、選択したアイテムもリセットされます!

Reflector を使用してコンボボックスのソースを検査しましたが、これは意図された動作であるようです。

これを回避する「いい」方法はありますか?私が達成したいのは、ユーザーが「会社A」を選択し、その後会社のリストをリロードすると、「会社A」が選択されたままになることです(新しいリストにあると仮定します)。

4

4 に答える 4

4

多分あなたObservableCollection<Company>の代わりに使うことができますIEnumerable<Company>か?次に、バックグラウンドの変更時に、新しいリストに新しい/存在しないアイテムのみを追加/削除します。選択したアイテムは、変更によって削除されない限り、そのままにしておく必要があります。

小さなハックアラウンドを使用して、監視可能なコレクションを別のスレッドで更新できます。

于 2010-02-09T12:20:41.790 に答える
1

うーん、それが「いい」方法かどうかはわかりませんが、リロードが発生する前に選択したアイテムにアクセスできる場合は、それ(またはそのキーなど)を保存し、リロード後にプログラムで再度選択することができます。終わり。

クイックモックアップ:

var selectedItem = myCombo.SelectedItem;
DoReload();
myCombo.SelectedItem = selectedItem;

しかし、私はあなたがこのマニュアルの回避策とは別の方法を意味していると思いますか?
これがとにかく役立つことを願っています...

UPDATE
わかりました、バックグラウンドスレッドからです。
ICollectionViewを使用してコンボボックスもバインドしていますか?その場合は、CurrentItemプロパティを使用して参照を保持できます。簡単なモックアップを作成しましたが、これは私のセットアップで機能しています。これは、UIへの参照があることを前提としています。

XAML

<Grid VerticalAlignment="Top">  
    <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <ComboBox ItemsSource="{Binding Items}" IsSynchronizedWithCurrentItem="True" Grid.Column="0" Grid.Row="0" DisplayMemberPath="Name"/>
    <Button Command="{Binding UpdateCommand}" Grid.Column="1" Grid.Row="0">Update</Button>
</Grid>

View / ViewModel

public partial class Window1 : Window {
   public Window1() {
        InitializeComponent();
        this.DataContext = new ViewModel(this);
   }
}

public class ViewModel
{
    private readonly Window1 window;
    private ObservableCollection<Item> items;
    private ICollectionView view;

    public ViewModel(Window1 window) {
        this.window = window;
        items = new ObservableCollection<Item>
            {
                new Item("qwerty"),
                new Item("hello"),
                new Item("world"),
            };

        view = CollectionViewSource.GetDefaultView(items);
    }

    public ObservableCollection<Item> Items { get { return items; } }

    public ICommand UpdateCommand {
        get { return new RelayCommand(DoUpdate); }
    }

    public Item SelectedItem { get; set; }

    private void DoUpdate(object obj) {
        var act = new Func<List<Item>>(DoUpdateAsync);
        act.BeginInvoke(CallBack, act);
    }

    private List<Item> DoUpdateAsync() {
        return new List<Item> {
                new Item("hello"),
                new Item("world"),
                new Item("qwerty"),
            };
    }

    private void CallBack(IAsyncResult result) {
        try {
            var act = (Func<List<Item>>)result.AsyncState;
            var list = act.EndInvoke(result);

            window.Dispatcher.Invoke(new Action<List<Item>>(delegate(List<Item> lst) {
                                                                    var current = lst.Single(i => i.Name == ((Item)view.CurrentItem).Name);
                                                                    Items.Clear();
                                                                    lst.ForEach(Items.Add);
                                                                    view.MoveCurrentTo(current);
                                                                }), list);

        } catch(Exception exc){ Debug.WriteLine(exc); }
    }
}

public class Item {
    public Item(string name) {
        Name = name; 
    }
    public string Name { get; set; }
}

選択したアイテムがリストに含まれなくなった場合に備えて、何らかの処理を行う必要があります。IsSynchronizedWithCurrentItem
プロパティは ここで重要です。そうでないと機能しません! また、メインウィンドウへの参照は、DIフレームワークによるものである必要があります。

于 2010-02-09T10:58:39.413 に答える
0

Yacoder が指摘したように、これはオブジェクトの等価性に関係しています。SelectedItem の代わりに SelectedValue をバインドする限り、ItemsSource を匿名型コレクションとして定義できます。そうすれば、この問題は発生しません (また、データベースから値を読み取る必要がある場合は高速です)。

于 2011-08-20T15:08:17.383 に答える