使用不同的列表多次创建itemscontrol

时间:2016-04-19 20:17:21

标签: wpf xaml itemscontrol

我正在尝试打印5张专辑,每张专辑都会打印所有'歌曲,并在每首歌曲旁边都有一个复选框。 (我建议你看下面发布的图片) 我尝试做的比使用ItemsControl,但我不知道怎么做,所以每个ItemsControl都会绑定另一个列表(带有特定专辑的歌曲)。

我在for循环中制作了所有5张专辑。

我的问题是:

  1. 对于每张专辑,如何为其“特定歌曲”创建ItemsControl 列表。
  2. 每次检查CheckBox时,都会检查其中的所有复选框 row(所有其他专辑)。
  3. 以下是单个ItemsControl的代码:

    <ItemsControl Grid.Column="1" ItemsSource="{Binding}"
                      Grid.IsSharedSizeScope="True"
                      Margin="12 0 12 0">
            <ItemsControl.ItemTemplate>
                <DataTemplate DataType="{x:Type domain:SelectableViewModel}">
                    <Border x:Name="Border" Padding="8">
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition SharedSizeGroup="Checkerz" />
                                <ColumnDefinition />
                            </Grid.ColumnDefinitions>
                            <CheckBox VerticalAlignment="Center" IsChecked="{Binding IsSelected}"/>
                            <StackPanel Margin="8 0 0 0" Grid.Column="1">
                                <TextBlock FontWeight="Bold" Text="{Binding Name}" />
                                <TextBlock Text="{Binding Description}" />
                            </StackPanel>
                        </Grid>
                    </Border>
                    <DataTemplate.Triggers>
                        <DataTrigger Binding="{Binding IsSelected}" Value="True">
                            <Setter TargetName="Border" Property="Background" Value="{DynamicResource MaterialDesignSelection}" />
    
                        </DataTrigger>
                    </DataTemplate.Triggers>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    

    这是一张现在看起来如何的图片。 (看红色方块): Click here

    请帮帮我:(

1 个答案:

答案 0 :(得分:0)

尝试下一个解决方案:

  

对于每张专辑,如何为其“特定歌曲”列表创建ItemsControl。

Udate#1 - Xaml代码解决方案

<Window x:Class="ListBoxOflistboxes.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:listBoxOflistboxes="clr-namespace:ListBoxOflistboxes"
    Title="MainWindow" Height="350" Width="525">

<Grid>
    <Grid.Resources>
        <DataTemplate x:Key="InnerItemsControl" DataType="{x:Type listBoxOflistboxes:AlbumViewModel}">
            <ItemsControl Grid.Column="1" ItemsSource="{Binding Songs}"
              Grid.IsSharedSizeScope="True"
              Margin="12 0 12 0">
                <ItemsControl.ItemTemplate>
                    <DataTemplate DataType="{x:Type listBoxOflistboxes:SelectableViewModel}">
                        <Border x:Name="Border" Padding="8">
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition SharedSizeGroup="Checkerz" />
                                    <ColumnDefinition />
                                </Grid.ColumnDefinitions>
                                <CheckBox VerticalAlignment="Center" IsChecked="{Binding IsSelected}"/>
                                <StackPanel Margin="8 0 0 0" Grid.Column="1">
                                    <TextBlock FontWeight="Bold" Text="{Binding Name}" />
                                    <TextBlock Text="{Binding Description}" />
                                </StackPanel>
                            </Grid>
                        </Border>
                        <DataTemplate.Triggers>
                            <DataTrigger Binding="{Binding IsSelected}" Value="True">
                                <Setter TargetName="Border" Property="Background" Value="Red" />
                            </DataTrigger>
                            <DataTrigger Binding="{Binding IsSelected}" Value="False">
                                <Setter TargetName="Border" Property="Background" Value="Transparent" />
                            </DataTrigger>
                        </DataTemplate.Triggers>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </DataTemplate>
        <DataTemplate x:Key="ListBoxItemDataTemplate" DataType="listBoxOflistboxes:AlbumViewModel">
            <ContentControl Content="{Binding }" ContentTemplate="{StaticResource InnerItemsControl}"></ContentControl>
        </DataTemplate>
    </Grid.Resources>
    <Grid.DataContext>
        <listBoxOflistboxes:MainAlbumsViewModel/>
    </Grid.DataContext>

    <ListBox ItemsSource="{Binding Albums}">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal"></StackPanel>
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
        <ListBox.ItemContainerStyle>
            <Style TargetType="ListBoxItem">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="ListBoxItem">
                            <Grid Margin="1">
                                <Border x:Name="MouseOverBorder" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                                        Background="LightGreen" BorderBrush="DimGray" BorderThickness="1.5" Visibility="Collapsed"/>
                                <Border x:Name="SelectedBorder" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                                        Background="Green" BorderBrush="Black" BorderThickness="1.5" Visibility="Collapsed"/>
                                <ContentPresenter Content="{TemplateBinding Content}"
                                                  ContentTemplate="{StaticResource ListBoxItemDataTemplate}" />
                            </Grid>
                            <ControlTemplate.Triggers>
                                <!--Uncomment these trigger in order to make the mouse over border to be visible-->
                                <!--<Trigger Property="ListBoxItem.IsMouseOver" Value="True">
                                    <Setter TargetName="MouseOverBorder" Property="Visibility" Value="Visible"/>
                                </Trigger>
                                <Trigger Property="ListBoxItem.IsMouseOver" Value="False">
                                    <Setter TargetName="MouseOverBorder" Property="Visibility" Value="Collapsed"/>
                                </Trigger>-->
                                <Trigger Property="ListBoxItem.IsSelected" Value="True">
                                    <Setter TargetName="SelectedBorder" Property="Visibility" Value="Visible"/>
                                </Trigger>
                                <Trigger Property="ListBoxItem.IsSelected" Value="False">
                                    <Setter TargetName="SelectedBorder" Property="Visibility" Value="Collapsed"/>
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </ListBox.ItemContainerStyle>
    </ListBox>

</Grid>

  

每次检查CheckBox时,它都会检查其'行(所有其他相册)中的所有复选框。

使用共享模型在视图模型中管理

    /// <summary>
/// main view model
/// </summary>
public class MainAlbumsViewModel:BaseObservableObject
{
    private readonly ISelectionEventAggregator _selectionEventAggregator;
    private readonly ISongsProvider _songsProvider;

    private ObservableCollection<AlbumViewModel> _albums;

    public MainAlbumsViewModel()
    {
        _selectionEventAggregator = new SelectionEventAggregator();
        _songsProvider = new SongsProvider();

        Albums = new ObservableCollection<AlbumViewModel>
        {
            new AlbumViewModel(_selectionEventAggregator, _songsProvider),
            new AlbumViewModel(_selectionEventAggregator, _songsProvider),
            new AlbumViewModel(_selectionEventAggregator, _songsProvider),
        };

        Albums.ToList().ForEach(model =>
        {
            _songsProvider.RegisterSongs(model, new List<SelectableViewModel>
            {
                new SelectableViewModel(_selectionEventAggregator){Name = "Song A", Description = "Description A"},
                new SelectableViewModel(_selectionEventAggregator){Name = "Song B", Description = "Description B"},
                new SelectableViewModel(_selectionEventAggregator){Name = "Song C", Description = "Description C"},
                new SelectableViewModel(_selectionEventAggregator){Name = "Song D", Description = "Description D"},
            });
        });
    }

    public ObservableCollection<AlbumViewModel> Albums
    {
        get { return _albums; }
        set
        {
            _albums = value;
            OnPropertyChanged();
        }
    }
}

/// <summary>
/// an album view-model
/// </summary>
public class AlbumViewModel:BaseObservableObject
{
    public AlbumViewModel(ISelectionEventAggregator selectionEventAggregator, ISongsProvider songsProvider)
    {
        _selectionEventAgreggator = selectionEventAggregator;
        _songsProvider = songsProvider;
        //you should think about an unsubscribe mechanism
        _selectionEventAgreggator.SelectionEventHandler += SelectionEventAgreggatorOnSelectionEventHandler;
    }

    private void SelectionEventAgreggatorOnSelectionEventHandler(object sender, SelectionEventArgs args)
    {
        var key = args.Key as SelectableViewModel;
        if(key == null) return;
        var existingSong = Songs.FirstOrDefault(model => model.Name.Equals(key.Name) && model.Description.Equals(key.Description));
        if(existingSong == null) return;
        existingSong.UpdateSelectionSilentely(args.IsSelected);
    }


    private ObservableCollection<SelectableViewModel> _songs;
    private readonly ISelectionEventAggregator _selectionEventAgreggator;
    private readonly ISongsProvider _songsProvider;

    public ObservableCollection<SelectableViewModel> Songs
    {
        get { return _songs ?? (_songs = new ObservableCollection<SelectableViewModel>(_songsProvider.GetSongs(this))); }
    }
}

/// <summary>
/// helps to provide songs
/// </summary>
public interface ISongsProvider
{
    List<SelectableViewModel> GetSongs(object albumKey);
    void RegisterSongs(object albumKey, IEnumerable<SelectableViewModel> songs);
}

class SongsProvider : ISongsProvider
{
    private Dictionary<object, List<SelectableViewModel>> _albums = new Dictionary<object, List<SelectableViewModel>>();
    public List<SelectableViewModel> GetSongs(object albumKey)
    {
        return _albums.ContainsKey(albumKey) == false ? null : _albums[albumKey];
    }

    public void RegisterSongs(object albumKey, IEnumerable<SelectableViewModel> songs)
    {
        if (_albums.ContainsKey(albumKey) == false)
        {
            if(songs == null) return;
            _albums.Add(albumKey, songs.ToList());
        }
        else
        {
            if (songs == null)
            {
                _albums.Remove(albumKey);
                return;
            }
            _albums[albumKey] = songs.ToList();
        }
    }
}

    /// <summary>
/// a single song view-model
/// </summary>
public class SelectableViewModel:BaseObservableObject
{
    private readonly ISelectionEventAggregator _selectionEventAggregator;
    private bool _isSelected;
    private string _name;
    private string _description;

    public SelectableViewModel(ISelectionEventAggregator selectionEventAggregator)
    {
        _selectionEventAggregator = selectionEventAggregator;
    }

    public bool IsSelected
    {
        get { return _isSelected; }
        set
        {
            _isSelected = value;
            OnPropertyChanged();
            _selectionEventAggregator.Publish(new SelectionEventArgs {Key = this, IsSelected = _isSelected});
        }
    }

    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            OnPropertyChanged();
        }
    }

    public string Description
    {
        get { return _description; }
        set
        {
            _description = value;
            OnPropertyChanged();
        }
    }

    public void UpdateSelectionSilentely(bool isSelected)
    {
        _isSelected = isSelected;
        OnPropertyChanged(() => IsSelected);
    }
}

/// <summary>
/// helps to manage selection
/// </summary>
public interface ISelectionEventAggregator
{
    event EventHandler<SelectionEventArgs> SelectionEventHandler;

    void Publish(SelectionEventArgs selectionEventArgs);
}

public class SelectionEventAggregator : ISelectionEventAggregator
{
    public event EventHandler<SelectionEventArgs> SelectionEventHandler;
    public void Publish(SelectionEventArgs selectionEventArgs)
    {
        OnSelectionEventHandler(selectionEventArgs);
    }

    protected virtual void OnSelectionEventHandler(SelectionEventArgs e)
    {
        var handler = SelectionEventHandler;
        if (handler != null) handler(this, e);
    }
}

public class SelectionEventArgs:EventArgs
{
    public object Key { get; set; }
    public bool IsSelected { get; set; }
}

BaseObservableObject - 简单的INPC

 /// <summary>
/// implements the INotifyPropertyChanged (.net 4.5)
/// </summary>
public class BaseObservableObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }

    protected virtual void OnPropertyChanged<T>(Expression<Func<T>> raiser)
    {
        var propName = ((MemberExpression)raiser.Body).Member.Name;
        OnPropertyChanged(propName);
    }

    protected bool Set<T>(ref T field, T value, [CallerMemberName] string name = null)
    {
        if (!EqualityComparer<T>.Default.Equals(field, value))
        {
            field = value;
            OnPropertyChanged(name);
            return true;
        }
        return false;
    }
}

<强>解释

问题第二部分的主要思想是使用某种事件聚合。

看起来如何 here

问候。