简体   繁体   English

使用 MVVM 在 WPF 中更改 ObservableCollection 时如何触发转换器?

[英]How to trigger converter when ObservableCollection is changed in WPF using MVVM?

I have two list like this:我有两个这样的列表:

<ListView Name="listView" Height="300" ItemsSource="{Binding Resultados}">
   <ListView.View>
      <GridView>
         <GridViewColumn>
            <GridViewColumn.CellTemplate>
               <DataTemplate>
                  <CheckBox
                     IsChecked="{Binding Path=CommandParameter, RelativeSource={RelativeSource Self}, Converter={StaticResource CheckBoxCeldaConverter}, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
                     Command="{Binding Path=DataContext.SeleccionarCeldaCommand, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" 
                     CommandParameter="{Binding}"/>
               </DataTemplate>
            </GridViewColumn.CellTemplate>
         </GridViewColumn>
         <GridViewColumn Header="EDIFICIO" DisplayMemberBinding="{Binding NIVEL.PASILLO.EDIFICIO.NOMBRE}"/>
         <GridViewColumn Header="PASILLO" DisplayMemberBinding="{Binding NIVEL.PASILLO.NOMBRE}"/>
         <GridViewColumn Header="NIVEL" DisplayMemberBinding="{Binding NIVEL.NOMBRE}"/>
         <GridViewColumn Header="CELDA" DisplayMemberBinding="{Binding CELDA.NOMBRE}"/>
         <GridViewColumn Header="CLASIFICACIÓN" DisplayMemberBinding="{Binding CELDA_CATEGORIA.NOMBRE}"/>
         <GridViewColumn>
            <GridViewColumn.CellTemplate>
               <DataTemplate>
                  <Button
                     Command="{Binding Path=DataContext.MostrarDiasVisitasCommand, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
                     CommandParameter="{Binding CELDA.CELDA_DIAS_VISITA}"
                     IsEnabled="{Binding TieneDiasVisita}">
                     <materialDesign:PackIcon Kind="Eye"/>
                  </Button>
               </DataTemplate>
            </GridViewColumn.CellTemplate>
         </GridViewColumn>
      </GridView>
   </ListView.View>
</ListView>
<ListView Name="listView2" Height="300" ItemsSource="{Binding CeldasSeleccionadas}" Grid.Column="1" Margin="20 0 0 0">
   <ListView.View>
      <GridView>
         <GridViewColumn Header="EDIFICIO" DisplayMemberBinding="{Binding NIVEL.PASILLO.EDIFICIO.NOMBRE}"/>
         <GridViewColumn Header="PASILLO" DisplayMemberBinding="{Binding NIVEL.PASILLO.NOMBRE}"/>
         <GridViewColumn Header="NIVEL" DisplayMemberBinding="{Binding NIVEL.NOMBRE}"/>
         <GridViewColumn Header="CELDA" DisplayMemberBinding="{Binding CELDA.NOMBRE}"/>
         <GridViewColumn Header="CLASIFICACIÓN" DisplayMemberBinding="{Binding CELDA_CATEGORIA.NOMBRE}"/>
         <GridViewColumn>
            <GridViewColumn.CellTemplate>
               <DataTemplate>
                  <Button
                     Command="{Binding Path=DataContext.BorrarCeldaCommand, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
                     CommandParameter="{Binding}">
                     <materialDesign:PackIcon Kind="Delete"/>
                  </Button>
               </DataTemplate>
            </GridViewColumn.CellTemplate>
         </GridViewColumn>
      </GridView>
   </ListView.View>
</ListView>

In the first list, the elements have a CheckBox, if the CheckBox is pressed, the element is added or removed from the second list that it's ItemSource is binded to CeldasSeleccionadas ObservableCollection in the ViewModel.在第一个列表中,元素有一个 CheckBox,如果按下 CheckBox,则从第二个列表中添加或删除元素,它的 ItemSource 绑定到 ViewModel 中的 CeldasSeleccionadas ObservableCollection。 I have a converter in the binding of the isChecked property of the first list that checks if the element is present in the CeldasSeleccionadas ObservableCollection, if is present, put the isChecked property as true.我在第一个列表的 isChecked 属性的绑定中有一个转换器,它检查元素是否存在于 CeldasSeleccionadas ObservableCollection 中,如果存在,则将 isChecked 属性设置为 true。 This is because if the user update the View, the selected values keeps checked.这是因为如果用户更新视图,选定的值会保持选中状态。

Now, in the second list, the one binded to CeldasSeleccionadas, I have a button to delete the element from CeldasSeleccionadas ObservableCollection.现在,在第二个列表中,即绑定到 CeldasSeleccionadas 的列表中,我有一个按钮可以从 CeldasSeleccionadas ObservableCollection 中删除元素。 This works fine, the only problem I have is that when I remove the element from CeldasSeleccionadas ObservableCollection the CheckBox in the first list keeps isChecked property as true, the converter is not beign called again and is not checking if the element exist in the CeldasSeleccionadas ObservableCollection.这工作正常,我唯一的问题是,当我从 CeldasSeleccionadas ObservableCollection 中删除元素时,第一个列表中的 CheckBox 将 isChecked 属性保持为真,转换器不会再次被调用,并且不检查元素是否存在于 CeldasSeleccionadas ObservableCollection .

CeldasSeleccionadas looks like this in the ViewModel: CeldasSeleccionadas 在 ViewModel 中看起来像这样:

public ObservableCollection<CeldaModel> CeldasSeleccionadas { get; set; } = new ObservableCollection<CeldaModel>();

This is the Command to add elements to CeldasSeleccionadas:这是向 CeldasSeleccionadas 添加元素的命令:

private ICommand _SeleccionarCeldaCommand;
public ICommand SeleccionarCeldaCommand {
  get {
    if (_SeleccionarCeldaCommand == null) _SeleccionarCeldaCommand = new RelayCommand(param =>SeleccionarCelda((CeldaModel) param));
    return _SeleccionarCeldaCommand;
  }
}
void SeleccionarCelda(CeldaModel celda) {
  if (CeldasSeleccionadas.Contains(celda)) {
    CeldasSeleccionadas.Remove(celda);
  }
  else {
    CeldasSeleccionadas.Add(celda);
  }
}

And this for remove elements:这用于删除元素:

private ICommand _BorrarCeldaCommand;
public ICommand BorrarCeldaCommand {
  get {
    if (_BorrarCeldaCommand == null) _BorrarCeldaCommand = new RelayCommand(param =>BorrarCelda((CeldaModel) param));
    return _BorrarCeldaCommand;
  }
}
void BorrarCelda(CeldaModel celda) {
  CeldasSeleccionadas.Remove(celda);
}

The Converter looks like this:转换器看起来像这样:

public class CheckBoxCeldaConverter : Freezable, IValueConverter
    {
        public CheckBoxCeldaConverter()
        {
            MyCollection = new ObservableCollection<CeldaModel>();
        }

        protected override Freezable CreateInstanceCore()
        {
            return new CheckBoxCeldaConverter();
        }


        public static readonly DependencyProperty MyCollectionProperty =
        DependencyProperty.Register(nameof(MyCollection),
            typeof(ObservableCollection<CeldaModel>), typeof(CheckBoxCeldaConverter),
            new FrameworkPropertyMetadata(null));

        public ObservableCollection<CeldaModel> MyCollection
        {
            get { return GetValue(MyCollectionProperty) as ObservableCollection<CeldaModel>; }
            set { SetValue(MyCollectionProperty, value); }
        }

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (MyCollection.Contains(value as CeldaModel))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

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

And I call it from my view inside the User.Resources like this:我从 User.Resources 内部的视图中调用它,如下所示:

<UserControl.Resources>
        <local:CheckBoxCeldaConverter MyCollection="{Binding CeldasSeleccionadas}" x:Key="CheckBoxCeldaConverter"/>
</UserControl.Resources>

How can I trigger the converter when a item from the CeldasSeleccionadas ObservableCollection is added or removed?添加或删除 CeldasSeleccionadas ObservableCollection 中的项目时,如何触发转换器?

Read all, it's more intuitive and explained than before.阅读全部,它比以前更直观和解释。

The code will be much easier if CeldaModel was aware of "I'm selected", letting you bind the checkbox to "Selected" boolean property.如果 CeldaModel 知道“我被选中”,代码会容易得多,让您将复选框绑定到“已选中”boolean 属性。

With that you can avoid the converter.这样你就可以避免转换器。

But I think there is a better choice.但我认为有更好的选择。

You have "Resultados".你有“结果”。

Then in you ViewModel creates two more properties ICollectionView然后在你的 ViewModel 中创建另外两个属性 ICollectionView

public class MasterViewModel : ViewModelBase //example{

    ObservableCollection<CeldaModel> Resultados{get; set;}

    ICollectionView TodosResultados{get; set;}

    ICollectionView ResultadosSeleccionados {get; set;} //You create ICollectionView and filter it by "Selected" property in CeldaModel

    ...

}

Bind one listview to "TodosResultados" and the other to "ResultadosSeleccionados"将一个列表视图绑定到“TodosResultados”,另一个绑定到“ResultadosSeleccionados”

If you have bound everything correctly (checkbox with Selected, ListViews with ICollectionView), you don't have to worry about nothing.如果您已正确绑定所有内容(带有 Selected 的复选框,带有 ICollectionView 的 ListViews),您就不必担心任何事情。 Everything will work like a charm.一切都会像魅力一样发挥作用。 At least in the surface.至少在表面上。

No need to create the "Commands" (unless the command make something in the back Model- don't mess up with the ViewModel).无需创建“命令”(除非命令在后面的模型中产生某些东西——不要弄乱 ViewModel)。

Warning: this work fine if you only want "View", if you want two ObservableCollection is valid too.警告:如果你只想要“视图”,这个工作很好,如果你想要两个 ObservableCollection 也是有效的。

PS: should you name "CeldaModel" "CeldaViewModel"? PS:你应该命名“CeldaModel”“CeldaViewModel”吗? In a pure MVVM, Model classes must not interact in any way with the view, even if you include it in a collection.在纯 MVVM 中,Model 类不得以任何方式与视图交互,即使您将其包含在集合中也是如此。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 WPF 将 ObservableCollection 与转换器绑定 - WPF binding ObservableCollection with converter WPF MVVM:如何在UI中反映ObservableCollection的更改 - WPF MVVM: How to reflect changes of ObservableCollection in the UI 在WPF MVVM中过滤ObservableCollection - Filtering ObservableCollection in WPF MVVM 将项目添加到绑定的ObservableCollection时未调用WPF Polyline的转换器 - WPF Polyline's converter not invoked when item added to bound ObservableCollection 当 ObservableCollection 中的 object 属性发生变化时,通知另一个属性 CommunityToolkit Mvvm - When object property in ObservableCollection changed, notify another property, CommunityToolkit Mvvm 使用NServiceBus时,MVVM中的ObservableCollection不变 - ObservableCollection not changing in MVVM when using NServiceBus 如果使用带有MVVM模式的wpf ItemsControl,如何将一个ObservableCollection作为ItemsSource绑定到不同的comboBoxes(模型)? - How to bind one ObservableCollection as ItemsSource to different comboBoxes (models) if using wpf ItemsControl with MVVM pattern? 刷新ObservableCollection <T> 当T中的属性更改时-WPF MVVM - Refresh ObservableCollection<T> when a property in T changes - WPF MVVM 如何在我的情况下使用mvvm绑定DataGrid(ObservableCollection内的ObservableCollection) - How to bind DataGrid in my situation using mvvm (ObservableCollection inside ObservableCollection) WPF ObservableCollection更新DataGrid MVVM - WPF ObservableCollection Updating DataGrid MVVM
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM