C# 正确的MVVM实现动态生成的usercontrol

C# 正确的MVVM实现动态生成的usercontrol,c#,wpf,mvvm,C#,Wpf,Mvvm,我的场景:我有一个usercontrol,由一个comboBox和一个TextBox组成。组合框应包含ObservableCollection中包含的数字 任务:ObservableCollection中的数字表示书籍章节的路径;因此,每一章都是独一无二的。意思:如果我有第1-5章,那么第一个userControl组合应该显示所有第1-5章(其中一个是随机选择的),第二个userControl组合包含所有章节,但不是前一个组合中选择的,依此类推。文本框用于章节的注释 到目前为止我所取得的成就:我

我的场景:我有一个usercontrol,由一个comboBox和一个TextBox组成。组合框应包含ObservableCollection中包含的数字

任务:ObservableCollection中的数字表示书籍章节的路径;因此,每一章都是独一无二的。意思:如果我有第1-5章,那么第一个userControl组合应该显示所有第1-5章(其中一个是随机选择的),第二个userControl组合包含所有章节,但不是前一个组合中选择的,依此类推。文本框用于章节的注释

到目前为止我所取得的成就:我目前没有模型;只有一个主视图模型(在我的例子中是ItemsViewModel)和一个用于我的userControl的视图模型(PathViewModel)。然后是主窗口视图

问题是:在我的主窗口上,我可以创建几个动态创建的用户控件。userControl文本框当前绑定到一个文本属性,而comboBox的索引绑定到另一个属性。但是我不知道: -如何访问特定用户控件的索引、选定项/值 -如何对组合框项/索引更改作出反应

这是我的密码: 用户控件

<UserControl>  <StackPanel Orientation="Horizontal">
    <ComboBox x:Name="combo" Margin="10" MinWidth="60" VerticalAlignment="Center" ItemsSource="{Binding AvailableNumbers}" SelectedIndex="{Binding TheIndex}" />
    <TextBox Margin="10" MinWidth="120" Text="{Binding TheText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
最后是我的UserControl视图模型:

public class PathViewModel : NotifyPropertyChangedBase
{

    public ObservableCollection<int> AvailableNumbers { get; set; } = new ObservableCollection<int>();

    private int _theIndex;

    public int TheIndex
    {
        get { return _theIndex; }
        set
        {
            _theIndex = value;
            OnPropertyChanged(ref _theIndex, value);
        }
    }

    private int _theValue;

    public int TheValue
    {
        get { return _theValue; }
        set
        {
            _theValue = value;
            OnPropertyChanged(ref _theValue, value);
        }
    }

    private string _theText;

    public string TheText
    {
        get { return _theText; }
        set
        {
            _theText = value;
            OnPropertyChanged(ref _theText, value);
        }
    }

    public PathViewModel()
    {

    }       

}
公共类PathViewModel:NotifyPropertyChangedBase
{
public ObservableCollection AvailableEnumbers{get;set;}=new ObservableCollection();
私人国际指数;
公共内部索引
{
获取{return\u theIndex;}
设置
{
_指数=数值;
已更改的房地产(参考指数、价值);
}
}
私人内部价值;
公共价值
{
获取{return\u theValue;}
设置
{
_价值=价值;
关于财产变更(参考价值,价值);
}
}
私有字符串_theText;
公共字符串文本
{
获取{return\u theText;}
设置
{
_文本=值;
已更改的属性(参考文本,值);
}
}
公共路径视图模型()
{
}       
}

任何关于如何从这里开始的提示都会得到高度重视。

因此关键是动态创建的每个
usercontrol
都应该创建一个
ViewModel
。因此,如果在
组合框中有
事件
,它将在
视图模型中触发。这一切都取决于您如何动态创建
usercontrols
您必须在资源中创建如上所述的数据模板,您可以在一个集合中生成您的ViewModels,该集合将创建您的
usercontrols
,然后您将拥有该集合中所有ViewModels的控件。可能您的
PathViewModel
可以存储选定的值并对其执行操作。因此,当您选择章节
PathViewModel
存储该决策时,您将创建一个存储该决策的章节。选择的索引将是复杂的,因为它必须考虑先前的选择。如何禁用已经选择的章节?Albin,所以我不能完全确定:数据模板在userControl.xaml上?如果是这样,代码隐藏的事件如何与我的viewModel交互?或者viewModel集合也是userControl viewModel的一部分?DataTemplate应位于父视图的resource或App.xaml或resource dictionary中。ViewModel集合应位于父ViewModel中。
public class ItemsViewModel : NotifyPropertyChangedBase    
{private int _aNumber;
 public int ANumber
{
get { return _aNumber; }
set { _aNumber = value;
OnPropertyChanged(ref _aNumber, value);
}
 }
 public ObservableCollection<PathViewModel> PathViewModels { get; set; } = new 
ObservableCollection<PathViewModel>();

    public ObservableCollection<int> AllNumbers { get; set; } = new ObservableCollection<int>();

    public ItemsViewModel()
    {
        UCCreationCommand = new CommandDelegateBase(UCCreationExecute, UCCreationCanExecute);
        UCDeletionCommand = new CommandDelegateBase(UCDeletionExecute, UCDeletionCanExecute);
        ReadoutCommand = new CommandDelegateBase(ReadoutExecute, ReadoutCanExecute);

        AllNumbers.Add(1);
        AllNumbers.Add(2);
        AllNumbers.Add(3);
        AllNumbers.Add(4);
        AllNumbers.Add(5);
    }

    private bool ReadoutCanExecute(object paramerter)
    {
        if (PathViewModels.Count > 0)
        {
            return true;
        }

        return false;
    }

    private void ReadoutExecute(object parameter)
    {
        //just for testing
    }

    public ICommand UCCreationCommand { get; set; }
    public ICommand UCDeletionCommand { get; set; }
    public ICommand ReadoutCommand { get; set; }


    private bool UCCreationCanExecute(object paramerter)
    {
        if (PathViewModels.Count < 8)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    private void UCCreationExecute(object parameter)
    {
        PathViewModel p = new PathViewModel();

        foreach (int i in AllNumbers)
        {
            p.AvailableNumbers.Add(i);
        }

        int rndIndex = 0;

        Random rnd = new Random();

        //creates a random chapter index
        rndIndex = rnd.Next(0, p.AvailableNumbers.Count);

        //just explicit for debugging reasons
        p.TheIndex = rndIndex;
        PathViewModels.Add(p);
    }

    private bool UCDeletionCanExecute(object paramerter)
    {
        if (PathViewModels.Count != 0)
        {
            return true;
        }
        else
        {
            return false;
        }

    }

    private void UCDeletionExecute(object parameter)
    {
        PathViewModel p = new PathViewModel();
        int delIndex = PathViewModels.Count - 1;

        p = PathViewModels[delIndex];

        AllNumbers.Add((int)p.TheValue+1);


        PathViewModels.Remove(p);
    }     

}
public class PathViewModel : NotifyPropertyChangedBase
{

    public ObservableCollection<int> AvailableNumbers { get; set; } = new ObservableCollection<int>();

    private int _theIndex;

    public int TheIndex
    {
        get { return _theIndex; }
        set
        {
            _theIndex = value;
            OnPropertyChanged(ref _theIndex, value);
        }
    }

    private int _theValue;

    public int TheValue
    {
        get { return _theValue; }
        set
        {
            _theValue = value;
            OnPropertyChanged(ref _theValue, value);
        }
    }

    private string _theText;

    public string TheText
    {
        get { return _theText; }
        set
        {
            _theText = value;
            OnPropertyChanged(ref _theText, value);
        }
    }

    public PathViewModel()
    {

    }       

}