WPF MVVM创建多个数据网格并将项目绑定到它们

时间:2017-07-24 10:29:30

标签: c# wpf mvvm binding

我在WPF绑定中遇到了以下问题。 我需要从XML文件加载对象并在列表框中创建已加载项目的列表,并在选择列表框项目时显示适当的对象集。

我可以用'code behind'风格来做,但我真的想以适当的MVVM方式做到这一点。 My Matrixes类由xsd2code生成,其中包含:

List<CorrectionMatrixType> correctionMatrixField;

并遵循

 public partial class CorrectionMatrixType {   
   public MatrixType A {get; set;}
   public MatrixType B {get; set;}
   public MatrixType C {get; set;}
... }

我如何通过Viewmodel创建'动态类似Grid的三个DataGrids,并将每个矩阵(A,B,C)绑定到哪个内容将根据列表框中选择的值更改?我知道要将我的MatrixType绑定到DataGrid,我必须使用ValueConverter将我的对象转换为二维数组。

也许我不得不承认我正在使用MVVM Light。

请提出任何建议?

2 个答案:

答案 0 :(得分:1)

我会使用INotifyPropertyChanged接口。这是一个小例子(不完全是你的情况,但我认为足以显示原理):

MatrixType类:

public class MatrixType
{
    public string Name { get; set; }

    public string Width { get; set; }

    public string Height { get; set; }

}

的Xaml:

 <Window.DataContext>
    <local:MainViewModel />
</Window.DataContext>
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="100"></ColumnDefinition>
        <ColumnDefinition Width="*"></ColumnDefinition>
    </Grid.ColumnDefinitions>
    <ListBox Grid.Column="0" ItemsSource="{Binding Items}" DisplayMemberPath="Name" SelectedItem="{Binding SelectedItem}"></ListBox>
    <Grid Grid.Column="1">
        <StackPanel Orientation="Vertical">
            <TextBox Text="{Binding SelectedItem.Name}" Height="30"/>
            <TextBox Text="{Binding SelectedItem.Height}" Height="30"/>
            <TextBox Text="{Binding SelectedItem.Width}" Height="30"/>
        </StackPanel>
    </Grid>
</Grid>

MainViewModel.cs:

public class MainViewModel : INotifyPropertyChanged
{
    public MainViewModel()
    {
        var list = new List<MatrixType>
        {
            new MatrixType {Height = "233", Name = "A", Width = "133"},
            new MatrixType {Height = "333", Name = "B", Width = "233"},
            new MatrixType {Height = "433", Name = "C", Width = "333"}
        };
        Items = new ObservableCollection<MatrixType>(list);
    }

    private MatrixType _selectedItem;
    public MatrixType SelectedItem
    {
        get => _selectedItem;
        set { _selectedItem = value; OnPropertyChanged(); }
    }

    public ObservableCollection<MatrixType> Items { get; set; }

    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

MainViewModel.cs(使用MVVM Light时):

public class MainViewModel : ObservableObject
{
    public MainViewModel()
    {
        var list = new List<MatrixType>
        {
            new MatrixType {Height = "233", Name = "A", Width = "133"},
            new MatrixType {Height = "333", Name = "B", Width = "233"},
            new MatrixType {Height = "433", Name = "C", Width = "333"}
        };
        Items = new ObservableCollection<MatrixType>(list);
    }

    private MatrixType _selectedItem;
    public MatrixType SelectedItem
    {
        get => _selectedItem;
        set { _selectedItem = value; RaisePropertyChanged(); }
    }

    public ObservableCollection<MatrixType> Items { get; set; }
}

答案 1 :(得分:0)

我自己写了解决方案,我不知道它是不是很好的MVVM解决方案。 我重新编写了我的XSD,因此MatrixType变为SimpleMatrix,现在:

XAML:

        <ListBox Margin="5,20,0,5" ItemsSource="{Binding CorrectionMatrixes}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding name}"/>
            </DataTemplate>
        </ListBox.ItemTemplate>
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="SelectionChanged">
                <command:EventToCommand Command="{Binding SelectionChangedCommand}" PassEventArgsToCommand="True"/>
            </i:EventTrigger>
            <i:EventTrigger EventName="Loaded">
                <command:EventToCommand Command="{Binding ListBoxLoadedCommand}" PassEventArgsToCommand="True"/>
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </ListBox>

<DataGrid CanUserAddRows="False"  HeadersVisibility="None" ItemsSource="{Binding CorrectionMatrixA, Converter={StaticResource MatrixToArray }}"/>

在我的viewmodel中:

    public RelayCommand<SelectionChangedEventArgs> SelectionChangedCommand => new RelayCommand<SelectionChangedEventArgs>(SelectionChanged);
    public RelayCommand<RoutedEventArgs> ListBoxLoadedCommand => new RelayCommand<RoutedEventArgs>(ListBoxLoaded);

    private string CorrectionMatrixName { get; set; }

    private void ListBoxLoaded(RoutedEventArgs obj)
    {
        if (obj.Source is ListBox listBox)
        {
            listBox.SelectedIndex = 0;
        }
    }

    private void SelectionChanged(SelectionChangedEventArgs obj)
    {
        if (obj.AddedItems.Count <= 0) return;
        if (obj.AddedItems[0] is CorrectionMatrix matrix)
        {
            CorrectionMatrixName = matrix.name;
        }
        RaisePropertyChanged(() => CorrectionMatrixA);
    }

    public SimpleMatrix CorrectionMatrixA
    {
        get
        {
            try
            {
                var x = Matrixes.Correction.Where(a => a.name == CorrectionMatrixName)
                            .Select(a => a.A).Single();
                return x;
            }
            catch (InvalidOperationException)
            {
                return null;
            }
        }
    }

矩阵由:

加载
Matrixes = settingsLoader.LoadMatrixes(Properties.Resources.MatrixesSettings);

这一切是如何运作的:

  1. 加载用户控件时=&gt;列表框上的选定索引设置为零

  2. 当列表框中的选定项目发生更改时,会触发更改CorrectionMatrixName的事件

  3. 绑定属性返回合适的矩阵,按名称

  4. 在数组中查找

    我不发布转换器代码 - 这里没关系。 多数民众赞成,我自己的解决方案对我有用。我希望它能帮助其他人