0

MVVM パターンを使用しており、完全に更新されていないデータバインド リストボックスがあります。

リストにバインドされているマシンの監視可能なコレクションを含むモデル ビューがあります。

<ListBox Name="MachinesList"
                         Height="300" 
                         Width="290" 
                         DataContext="{Binding Path=AllMachines}"
                         SelectionMode="Single"
                         ItemsSource="{Binding}" SelectionChanged="MachinesList_SelectionChanged"
                         HorizontalAlignment="Right"
                         >

コレクション AllMachines には、マシンの名前と場所を示す MachineView にバインドされている MachineModelViews の監視可能なコレクションが含まれています。

<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
            <Label Name="NameLabel" Content="{Binding Path=Name}" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Width="50" />
            <Label Content="Location:" Width="120"
                HorizontalAlignment="Right"
                HorizontalContentAlignment="Center"
                VerticalContentAlignment="Center"
                Target="{Binding ElementName=locationLabel}" 
            />
            <Label Content="{Binding Path=Location.Name}" Name="locationLabel" HorizontalContentAlignment="Center" Width="60"/>
</StackPanel>

問題:

コレクションに値が追加されると、問題なく更新されます。ただし、マシンが削除されると、Location.Name にバインドされたラベルのみが更新され、他の 2 つはリストボックスに残ります。コレクションが実際に MachineModelView を正しく更新および削除していることを確認しましたが、アプリケーションが再起動されるまで、その名前のラベルと「場所:」の「ラベル ラベル」がどのように存在し続けるかを確認しました。

前:

ここに画像の説明を入力

削除後:

ここに画像の説明を入力

アプリの再起動後:

ここに画像の説明を入力

削除ボタンは、AllMachines プロパティをサポートするプライベート メンバーとリポジトリ (最終的には Entity Framework を介してデータベースにプラグインする) からアイテムを削除するコマンドを呼び出します。

    RelayCommand _deleteCommand;

    public ICommand DeleteCommand
    {
        get
        {
            if (_deleteCommand == null)
            {
                _deleteCommand = new RelayCommand(
                    param => this.Delete(),
                    null
                    );
            }
            return _deleteCommand;
        }
    }

    void Delete()
    {
        if (_selectedMachine != null && _machineRepository.GetMachines().
            Where(i => i.Name == _selectedMachine.Name).Count() > 0)
        {
            _machineRepository.RemoveMachine(_machineRepository.GetMachines().
                Where(i => i.Name == _selectedMachine.Name).First());
            _allMachines.Remove(_selectedMachine);
        }
    }

注: AllMachines には名前を持つアイテムが 1 つしか存在できないため (これは、リポジトリとコマンド自体の追加ロジックによって処理されます)、「最初の」アイテムを削除しても問題ありません。

AllMachines プロパティ:

public ObservableCollection<MachineViewModel> AllMachines
    {
        get
        {
            if(_allMachines == null)
            {
                List<MachineViewModel> all = (from mach in _machineRepository.GetMachines()
                                              select new MachineViewModel(mach, _machineRepository)).ToList();
                _allMachines = new ObservableCollection<MachineViewModel>(all);
            }
            return _allMachines;
        }
        private set
        {
            _allMachines = value;
        }
    }

選択変更イベント ハンドラー:

private void MachinesList_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (e.AddedItems.Count > 0 && e.AddedItems[0] is MachineViewModel)
            ((MachinesViewModel)this.DataContext).SelectedMachine = (MachineViewModel)e.AddedItems[0];
    }
4

4 に答える 4

0

ここで述べた方法でコーディングすれば、すべてが機能するはずです。欠落しているコード部分を投稿してください:

  • あなたの AllMaschines プロパティ
  • MachinesList_SelectionChanged イベント <-- MVVM を実行する場合、これはほとんど必要ありません

次のことを確認するために、Delete() メソッドをデバッグしてください。がヒットし、そのマシンは本当にあなたのコレクションから削除されます。

于 2012-07-30T07:48:37.133 に答える
0
_machineRepository.RemoveMachine(_machineRepository.GetMachines().
            Where(i => i.Name == _selectedMachine.Name).First());
        AllMachines.Remove(_selectedMachine);

フィールド _allMachines.Remove の代わりに、AllMachines のようにプロパティから直接削除します

AllMachines.Remove

これが役立つことを願っています。

于 2012-07-30T04:15:15.053 に答える
0

私の問題は本当にばかげていることがわかりました。リポジトリが更新されたときに発生するイベントがあります。以前は追加コマンドしかなく、この問題が発生したときに削除する機能を追加していました。AllMachines プロパティのソースである内部変数を更新するために、イベントが MachinesModelView によって処理されていたことがわかります。

void OnMachineAddedToRepository(object sender, MachineAddedOrRemovedEventArgs e)
    {
        var viewModel = new MachineViewModel(e.NewMachine, _machineRepository);
        this.AllMachines.Add(viewModel);
    }

追加と削除を切り替えるようにイベント引数を変更しましたが、イベント ハンドラーを更新するのを忘れていました。今はうまくいきます:

void OnMachineAddedOrRemovedFromRepository(object sender, MachineAddedOrRemovedEventArgs e)
    {
        if (e.Added)
        {
            var viewModel = new MachineViewModel(e.NewMachine, _machineRepository);
            this.AllMachines.Add(viewModel);
        }
        else if (AllMachines.Where(i => i.Name == e.NewMachine.Name).Count() > 0)
            AllMachines.Remove(AllMachines.Where(i => i.Name == e.NewMachine.Name).First());
    }

これを追跡するのが非常に困難になったのは、Delete コマンドの AllMachines.Remove 部分が実行されるまで、余分な項目が非常に短時間しか存在しなかったためです。そのため、削除前のカウントと削除後のカウントを確認すると、アイテムがリポジトリから削除されている途中で、アイテムを追加し直してこの奇妙な状態のままにしたイベントを発生させたのは根性でした。MachineModelView の場所の部分だけが一貫して浮かんでいるのは奇妙なことです。ここで、イベント ハンドラーに _allMachines 変数の項目を追加または削除させ、delete コマンドで明示的に触れないようにします (delete コマンドはリポジトリから項目を削除するだけで、UI 変数がほんの一瞬で追いつくようにします)。イベントがトリガーされるまでに時間がかかります)。助けてくれてありがとう。

于 2012-07-30T19:31:34.127 に答える
0

'AllMachines が実際の観察可能なコレクションである場合、itemssource をデータ コンテキストにバインドする代わりにそれにバインドし、viewmodel をデータ コンテキストとしてバインドします。itemssource のバインド後に updatesourcetrigger を呼び出すことも役立つ場合があります。

 DataContext="{Binding Path=YourViewModel}"
                     SelectionMode="Single"
                     ItemsSource="{Binding AllMachines, UpdateSourceTrigger="PropertyChanged"}"

そして、その updatesourcetrigger を、一部のラベルだけでなく、バ​​インドしている場所でも使用できます。それ以外は、あなたの xaml は問題ないように見えます。

于 2012-07-30T01:04:07.093 に答える