2015-05-11 194 views
0

我有要求为每个应用程序仅选择/映射一些数据源,方法是首先选择左侧的应用程序,然后选择映射/选定的应用程序(很少)右边的数据源(见截图)。将模型的集合绑定到另一个集合的仅一部分

我经常有这样的场景作为业务需求,但我无法想出一个很好的解决方案来使用WPF绑定进行建模。

考虑下面的代码:

的车型:

class DataSource 
{ 
    public DataSource(string name) 
    { 
     Name = name; 
    } 

    public string Name { get; private set; } 
} 

class SoftwareSolution 
{ 
    public SoftwareSolution(string name) 
    { 
     Name = name; 
     this.DataSources = new ObservableCollection<DataSource>(); 
    } 

    public string Name { get; private set; } 
    public ObservableCollection<DataSource> DataSources { get; private set; } 
} 

class MainWindowViewModel 
{ 
    public MainWindowViewModel() 
    { 
     this.SoftwareSolutions = new ObservableCollection<SoftwareSolution>(); 
     this.SoftwareSolutions.Add(new SoftwareSolution("Software 1")); 
     this.SoftwareSolutions.Add(new SoftwareSolution("Software 2")); 
     this.SoftwareSolutions.Add(new SoftwareSolution("Software 3")); 

     this.AllAvailableDatasources = new ObservableCollection<DataSource>(); 
     this.AllAvailableDatasources.Add(new DataSource("SQL Server")); 
     this.AllAvailableDatasources.Add(new DataSource("Oracle")); 
     this.AllAvailableDatasources.Add(new DataSource("DB2")); 
     this.AllAvailableDatasources.Add(new DataSource("MySQL")); 
    } 

    public ObservableCollection<DataSource> AllAvailableDatasources { get; private set; } 
    public ObservableCollection<SoftwareSolution> SoftwareSolutions { get; private set; } 
} 

XAML:

<Grid> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="1*"/> 
     <ColumnDefinition Width="1*"/> 
    </Grid.ColumnDefinitions> 

    <TextBlock Text="Application" /> 
    <ListBox Margin="0,25,5,0" VerticalAlignment="Stretch" ItemsSource="{Binding SoftwareSolutions}" DisplayMemberPath="Name" /> 

    <TextBlock Grid.Column="1" Text="DataSources" /> 
    <ListBox Grid.Column="1" Margin="0,25,0,0" VerticalAlignment="Stretch" ItemsSource="{Binding AllAvailableDatasources}"> 
     <ListBox.ItemTemplate> 
      <DataTemplate> 
       <DockPanel> 
        <!-- how should I bind this checkbox? --> 
        <CheckBox DockPanel.Dock="Left" /> 
        <TextBlock DockPanel.Dock="Left" Text="{Binding Name}" Margin="5,0,0,0" /> 
       </DockPanel> 
      </DataTemplate> 
     </ListBox.ItemTemplate> 
    </ListBox> 
</Grid> 

的GUI:

example gui

我可以使用什么模式将右侧的复选框“绑定”到右侧的选择?

+0

我所做的就是创建一个包含类似'ItemsSource','SelectedItems'和'ItemTemplate'它包装在一个视图模型与'IsSelected'物业项目,并相应地更新'SelectedItems'集合属性的自定义控制。然后,使用模板,您可以以任何您想要的方式呈现项目(如“列表框”,“组合框”等)。这有点大惊小怪,但是因为我的项目使用这个控件50次以上,所以这是非常值得的。 – Grx70

回答

1

你需要一个DataSourceVM具有DataSourceIsSelected财产。每个SoftwareSolution都有自己的DataSourceVMs集合,并且复选框绑定到IsSelected

public SoftwareSolution(string name, IEnumerable<DataSource> dataSources) 
{ 
    Name = name; 
    this.DataSources = new ObservableCollection<DataSourceVM>(dataSource.Select(x => new DataSourceVM(x)); 
} 
+0

该解决方案将解决'IsSelected'绑定问题,但是现在我必须手动将'DataSourceVMs'的所有集合与'AllAvailableDatasources'同步,对吗? – GameScripting

+0

正确,但您应该先填充AllAvailableDatasources,然后将其传递到每个SoftwareSolution的构造函数中。如上所示,使用Linq创建DataSourceVMs并不重要。 – GazTheDestroyer

+0

当AllAvailableDatasources也可以动态更改时,我会知道它有问题。 – GameScripting

0

您应该使用ICollectionView来过滤ObservableCollection,这是这类场景中的标准方法。

特别是您将在左侧连接一个事件,它将更改ICollectionView,并将绑定在右侧的列上。

对这里的ICollectionView更多的相关信息:https://msdn.microsoft.com/en-us/library/system.componentmodel.icollectionview%28v=vs.110%29.aspx

+0

在过滤器中使用'ICollectionView'会导致Oracle和MySQL根本不在列表中,因为它们不是列表框绑定到的视图的一部分。我错过了什么? – GameScripting

相关问题