我正在尝试打印5张专辑,每张专辑都会打印所有'歌曲,并在每首歌曲旁边都有一个复选框。 (我建议你看下面发布的图片)
我尝试做的比使用ItemsControl
,但我不知道怎么做,所以每个ItemsControl
都会绑定另一个列表(带有特定专辑的歌曲)。
我在for
循环中制作了所有5张专辑。
我的问题是:
ItemsControl
列表。CheckBox
时,都会检查其中的所有复选框
row(所有其他专辑)。以下是单个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
请帮帮我:(
答案 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;
}
}
<强>解释强>
问题第二部分的主要思想是使用某种事件聚合。
问候。