WPF MVVM通过事件将UserControl从一个ObservableCollection移动到另一个ObservableCollection

时间:2015-03-25 18:50:31

标签: c# wpf mvvm observablecollection

我有一个包含2个ScrollViewers的清单视图。一个清单用于不完整的项目,另一个用于完整的项目。它们由2个独立的可观察集合填充,并由ItemsControls绑定。

UserControl有一个按钮,点击后会移动'检查'到另一个集合。

目前我进行此设置的方式是在ViewModel中,UserControl的DataContext有一个公共事件,主要窗口的VM使用以下方式订阅:

((CheckItemVM) ((CheckListItem) cli).DataContext).CompleteChanged += OnCompleteChanged;

其中cli是核对表项目。

然后OnCompleteChanged使用:

找到适当的View对象
foreach (object aCheck in Checks)
        {
            if (aCheck.GetType() != typeof (CheckListItem)) continue;
            if (((CheckListItem) aCheck).DataContext == (CheckItemVM) sender)
            {
                cliToMove = (CheckListItem) aCheck;
                break;
            }
        }

很明显,这打破了MVVM,我正在寻找解决方法(CheckListItem是View,而CheckItemVM是它的DataContext ViewModel)。盒装类型的推理是我有另一个UserControl,它们内部都有实例,基本上是部分标签,我需要能够对checklistitem与特定部分之间存在关联的可观察集合进行排序按名称。

1 个答案:

答案 0 :(得分:4)

这可以在MVVM中使用命令和绑定来完成....

我在这里提出的想法是在Windows视图模型中创建一个命令来管理check命令,并使用此命令在params中接收项视图模型,然后管理命令中的内容。我将使用MvvmLight库向您展示一个简单的示例:

enter image description here

模特:

public class ItemViewModel : ViewModelBase
{
    #region Name

    public const string NamePropertyName = "Name";

    private string _name = null;

    public string Name
    {
        get
        {
            return _name;
        }

        set
        {
            if (_name == value)
            {
                return;
            }

            RaisePropertyChanging(NamePropertyName);
            _name = value;
            RaisePropertyChanged(NamePropertyName);
        }
    }

    #endregion

    #region IsChecked

    public const string IsCheckedPropertyName = "IsChecked";

    private bool _myIsChecked = false;
    public bool IsChecked
    {
        get
        {
            return _myIsChecked;
        }
        set
        {
            if (_myIsChecked == value)
            {
                return;
            }

            RaisePropertyChanging(IsCheckedPropertyName);
            _myIsChecked = value;
            RaisePropertyChanged(IsCheckedPropertyName);
        }
    }

    #endregion

}

具有两个属性的简单模型,一个用于名称(标识符),另一个用于检查状态。

现在在主视图模型中,(或者你想要的Windows视图模型)....

首先是集合,一个用于已检查的项目,另一个用于未经检查的项目:

    #region UncheckedItems

    private ObservableCollection<ItemViewModel> _UncheckedItems;

    public ObservableCollection<ItemViewModel> UncheckedItems
    {
        get { return _UncheckedItems ?? (_UncheckedItems = GetAllUncheckedItems()); }
    }

    private ObservableCollection<ItemViewModel> GetAllUncheckedItems()
    {
        var toRet = new ObservableCollection<ItemViewModel>();

        foreach (var i in Enumerable.Range(1,10))
        {
            toRet.Add(new ItemViewModel {Name = string.Format("Name-{0}", i), IsChecked = false});
        }

        return toRet;
    }        

    #endregion

    #region CheckedItems

    private ObservableCollection<ItemViewModel> _CheckedItems;

    public ObservableCollection<ItemViewModel> CheckedItems
    {
        get { return _CheckedItems ?? (_CheckedItems = GetAllCheckedItems()); }
    }

    private ObservableCollection<ItemViewModel> GetAllCheckedItems()
    {
        var toRet = new ObservableCollection<ItemViewModel>();

        foreach (var i in Enumerable.Range(11, 20))
        {
            toRet.Add(new ItemViewModel { Name = string.Format("Name-{0}", i), IsChecked = true });
        }

        return toRet;
    }

    #endregion

命令:

    #region CheckItem

    private RelayCommand<ItemViewModel> _CheckItemCommand;

    public RelayCommand<ItemViewModel> CheckItemCommand
    {
        get { return _CheckItemCommand ?? (_CheckItemCommand = new RelayCommand<ItemViewModel>(ExecuteCheckItemCommand, CanExecuteCheckItemCommand)); }
    }

    private void ExecuteCheckItemCommand(ItemViewModel item)
    {
        //ComandCode
        item.IsChecked = true;
        UncheckedItems.Remove(item);
        CheckedItems.Add(item);
    }

    private bool CanExecuteCheckItemCommand(ItemViewModel item)
    {
        return true;
    }

    #endregion

这里的魔法可能在数据绑定中,在这种情况下我使用命令参数和FindAncestor绑定,检查数据模板:

        <DataTemplate x:Key="UncheckedItemDataTemplate">
            <Grid>
                <StackPanel Orientation="Horizontal">
                    <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding Name}" VerticalAlignment="Top"/>
                    <CheckBox HorizontalAlignment="Left" VerticalAlignment="Top" IsChecked="{Binding IsChecked}" IsEnabled="False"/>
                    <Button Content="Check" Width="75" Command="{Binding DataContext.CheckItemCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindow}}}" CommandParameter="{Binding Mode=OneWay}"/>
                </StackPanel>
            </Grid>
        </DataTemplate>
        <DataTemplate x:Key="CheckedItemDataTemplate">
            <Grid>
                <StackPanel Orientation="Horizontal">
                    <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding Name}" VerticalAlignment="Top"/>
                    <CheckBox HorizontalAlignment="Left" VerticalAlignment="Top" IsChecked="{Binding IsChecked}" IsEnabled="False"/>
                </StackPanel>
            </Grid>
        </DataTemplate>

已检查项目的一个数据模板,另一个未检查项目的数据模板。现在使用,这更简单:

    <ListBox Grid.Row="2" Margin="5" ItemsSource="{Binding UncheckedItems}" ItemTemplate="{DynamicResource UncheckedItemDataTemplate}"/>
    <ListBox Grid.Row="2" Margin="5" Grid.Column="1" ItemsSource="{Binding CheckedItems}" ItemTemplate="{DynamicResource CheckedItemDataTemplate}"/>

这是一个更清洁的解决方案,希望是有帮助的。