now you can use ItemsSource on Carousel

This commit is contained in:
NaBian committed 2020-05-13 23:52:45 +08:00
1 parent f4a0c6fd4f
commit a794c2a2c0
6 files changed
+259 -34

No files matched your search

@@ -9,7 +9,7 @@
<Image Width="300" Stretch="UniformToFill" Source="/HandyControlDemo;component/Resources/Img/2.jpg"/>
<hc:SimplePanel Width="600">
<Image Stretch="UniformToFill" Source="/HandyControlDemo;component/Resources/Img/3.jpg"/>
<TextBlock Text="示例文本" Style="{StaticResource TextBlockDefault}" FontSize="100" FontWeight="Bold" Foreground="White"/>
<TextBlock Text="Demo Text" Style="{StaticResource TextBlockDefault}" FontSize="100" FontWeight="Bold" Foreground="White"/>
</hc:SimplePanel>
<Image Width="600" Stretch="UniformToFill" Source="/HandyControlDemo;component/Resources/Img/4.jpg"/>
<Image Width="600" Stretch="UniformToFill" Source="/HandyControlDemo;component/Resources/Img/5.jpg"/>
@@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
@@ -21,13 +22,11 @@ namespace HandyControl.Controls
[DefaultProperty("Items")]
[ContentProperty("Items")]
[TemplatePart(Name = ElementPanelPage, Type = typeof(Panel))]
[TemplatePart(Name = ElementItemsControl, Type = typeof(ItemsPresenter))]
public class Carousel : ListBox, IDisposable
public class Carousel : SimpleItemsControl, IDisposable
{
#region Constants
private const string ElementPanelPage = "PART_PanelPage";
private const string ElementItemsControl = "PART_ItemsControl";
#endregion Constants
@@ -39,8 +38,6 @@ namespace HandyControl.Controls
private bool _appliedTemplate;
private ItemsPresenter _itemsControl;
private int _pageIndex = -1;
private RadioButton _selectedButton;
@@ -49,6 +46,12 @@ namespace HandyControl.Controls
private readonly List<double> _widthList = new List<double>();
private readonly Dictionary<object, CarouselItem> _entryDic = new Dictionary<object, CarouselItem>();
private bool _isRefresh;
private IEnumerable _itemsSourceInternal;
#endregion Data
public override void OnApplyTemplate()
@@ -59,7 +62,6 @@ namespace HandyControl.Controls
base.OnApplyTemplate();
_itemsControl = GetTemplateChild(ElementItemsControl) as ItemsPresenter;
_panelPage = GetTemplateChild(ElementPanelPage) as Panel;
if (!CheckNull()) return;
@@ -75,7 +77,7 @@ namespace HandyControl.Controls
UpdatePageButtons(_pageIndex);
}
private bool CheckNull() => !(_itemsControl == null || _panelPage == null);
private bool CheckNull() => _panelPage != null;
public static readonly DependencyProperty AutoRunProperty = DependencyProperty.Register(
"AutoRun", typeof(bool), typeof(Carousel), new PropertyMetadata(ValueBoxes.FalseBox, (o, args) =>
@@ -153,13 +155,6 @@ namespace HandyControl.Controls
}
}
protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
{
base.OnItemsChanged(e);
UpdatePageButtons();
}
/// <summary>
/// 是否自动跳转
/// </summary>
@@ -239,14 +234,14 @@ namespace HandyControl.Controls
_widthList.Clear();
_widthList.Add(0);
var width = .0;
foreach (FrameworkElement item in Items)
foreach (FrameworkElement item in ItemsHost.Children)
{
item.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
width += item.DesiredSize.Width;
_widthList.Add(width);
}
_itemsControl.Width = _widthList.Last() + ExtendWidth;
ItemsHost.Width = _widthList.Last() + ExtendWidth;
_panelPage.Children.Clear();
for (var i = 0; i < count; i++)
{
@@ -278,14 +273,14 @@ namespace HandyControl.Controls
if (Items.Count == 0) return;
if (!IsCenter)
{
_itemsControl.BeginAnimation(MarginProperty,
ItemsHost.BeginAnimation(MarginProperty,
AnimationHelper.CreateAnimation(new Thickness(-_widthList[PageIndex], 0, 0, 0)));
}
else
{
var ctl = (FrameworkElement)Items[PageIndex];
var ctl = (FrameworkElement)ItemsHost.Children[PageIndex];
var ctlWidth = ctl.DesiredSize.Width;
_itemsControl.BeginAnimation(MarginProperty,
ItemsHost.BeginAnimation(MarginProperty,
AnimationHelper.CreateAnimation(
new Thickness(-_widthList[PageIndex] + (ActualWidth - ctlWidth) / 2, 0, 0, 0)));
}
@@ -313,5 +308,149 @@ namespace HandyControl.Controls
private void ButtonPrev_OnClick(object sender, RoutedEventArgs e) => PageIndex--;
private void ButtonNext_OnClick(object sender, RoutedEventArgs e) => PageIndex++;
protected override DependencyObject GetContainerForItemOverride() => new CarouselItem();
protected override bool IsItemItsOwnContainerOverride(object item) => item is CarouselItem;
private void ClearItems()
{
ItemsHost?.Children.Clear();
_entryDic.Clear();
}
private void RemoveItem(object item)
{
if (_entryDic.TryGetValue(item, out var entry))
{
ItemsHost.Children.Remove(entry);
Items.Remove(item);
_entryDic.Remove(item);
}
}
protected override void Refresh()
{
if (ItemsHost == null) return;
_entryDic.Clear();
_isRefresh = true;
foreach (var item in Items)
{
AddItem(item);
}
_isRefresh = false;
}
private void AddItem(object item) => InsertItem(_entryDic.Count, item);
private void InsertItem(int index, object item)
{
if (ItemsHost == null)
{
Items.Insert(index, item);
_entryDic.Add(item, null);
}
else
{
DependencyObject container;
if (IsItemItsOwnContainerOverride(item))
{
container = item as DependencyObject;
}
else
{
container = GetContainerForItemOverride();
PrepareContainerForItemOverride(container, item);
}
if (container is CarouselItem element)
{
element.Style = ItemContainerStyle;
_entryDic[item] = element;
ItemsHost.Children.Insert(index, element);
if (IsLoaded && !_isRefresh && _itemsSourceInternal != null)
{
Items.Insert(index, item);
}
}
}
}
protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
{
if (_itemsSourceInternal != null)
{
if (_itemsSourceInternal is INotifyCollectionChanged s)
{
s.CollectionChanged -= InternalCollectionChanged;
}
Items.Clear();
ClearItems();
}
_itemsSourceInternal = newValue;
if (_itemsSourceInternal != null)
{
if (_itemsSourceInternal is INotifyCollectionChanged s)
{
s.CollectionChanged += InternalCollectionChanged;
}
foreach (var item in _itemsSourceInternal)
{
AddItem(item);
}
}
}
private void InternalCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (ItemsHost == null) return;
if (e.Action == NotifyCollectionChangedAction.Reset)
{
if (_entryDic.Count == 0) return;
ClearItems();
Items.Clear();
return;
}
if (e.OldItems != null)
{
foreach (var item in e.OldItems)
{
RemoveItem(item);
}
}
if (e.NewItems != null)
{
var count = 0;
foreach (var item in e.NewItems)
{
var index = e.NewStartingIndex + count++;
InsertItem(index, item);
}
}
}
protected override void OnItemsChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (_itemsSourceInternal != null) return;
InternalCollectionChanged(sender, e);
}
protected override void OnItemTemplateChanged(DependencyPropertyChangedEventArgs e)
{
}
protected override void OnItemContainerStyleChanged(DependencyPropertyChangedEventArgs e)
{
}
}
}
@@ -0,0 +1,9 @@
using System.Windows.Controls;
namespace HandyControl.Controls
{
public class CarouselItem : ContentControl
{
}
}
@@ -76,10 +76,7 @@ namespace HandyControl.Controls
{
base.OnApplyTemplate();
if (_viewContent.Style == null)
{
_viewContent.Style = CoverViewContentStyle;
}
_viewContent.Style ??= CoverViewContentStyle;
if (_selectedItem != null)
{
@@ -181,9 +178,7 @@ namespace HandyControl.Controls
}
_isRefresh = false;
GenerateIndex();
UpdateCoverViewContent(_viewContent.IsOpen);
}
@@ -338,10 +333,7 @@ namespace HandyControl.Controls
{
SetBindingForItem(element);
element.Style = ItemContainerStyle;
if (element.Header == null)
{
element.Header = item;
}
element.Header ??= item;
_entryDic[item] = element;
ItemsHost.Children.Insert(index, element);
@@ -26,6 +26,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Controls\Base\AdornerElement.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Controls\Block\FloatingBlock.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Controls\Button\SplitButton.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Controls\Carousel\CarouselItem.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Controls\Growl\GrowlWindow.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Controls\Image\ImageBlock.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Controls\Input\PinBox.cs" />
@@ -143,7 +144,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Controls\Loading\LoadingLine.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Controls\Other\AnimationPath.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Controls\Other\Badge.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Controls\Other\Carousel.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Controls\Carousel\Carousel.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Controls\Other\ChatBubble.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Controls\ColorPicker\ColorPicker.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Controls\Other\Dialog.cs" />
@@ -6,10 +6,94 @@
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Basic/Paths.xaml"/>
<ResourceDictionary Source="Button.xaml"/>
<ResourceDictionary Source="ListBox.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style x:Key="CarouselListBoxItemStyle" BasedOn="{StaticResource ListBoxItemCustom}" TargetType="ListBoxItem">
<Style x:Key="CarouselItemBaseStyle" TargetType="controls:CarouselItem">
<Setter Property="Focusable" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:CarouselItem">
<Border BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}">
<ContentPresenter Margin="{TemplateBinding Padding}" ContentTemplate="{Binding ItemTemplate,RelativeSource={RelativeSource AncestorType=controls:Carousel}}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="CarouselPateButton" BasedOn="{StaticResource BaseStyle}" TargetType="RadioButton">
<Setter Property="Margin" Value="5,0"/>
<Setter Property="Width" Value="10"/>
<Setter Property="Height" Value="10"/>
<Setter Property="Background" Value="White"/>
<Setter Property="BorderBrush" Value="{DynamicResource PrimaryBrush}"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Border CornerRadius="5" SnapsToDevicePixels="true" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}"/>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Opacity" Value=".9"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Opacity" Value=".6"/>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Background" Value="{DynamicResource PrimaryBrush}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="controls:Carousel">
<Setter Property="PageButtonStyle" Value="{StaticResource CarouselPateButton}"/>
<Setter Property="ItemContainerStyle" Value="{StaticResource CarouselItemBaseStyle}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:Carousel">
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.MouseEnter">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="GridTop" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:.1"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="FrameworkElement.MouseLeave">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="GridTop" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:.1"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
<controls:SimplePanel ClipToBounds="True">
<StackPanel x:Name="PART_Panel" Orientation="Horizontal"/>
<!--<ItemsPresenter x:Name="PART_ItemsControl" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" HorizontalAlignment="Left"/>-->
<controls:SimplePanel x:Name="GridTop" Opacity="0">
<Button Command="interactivity:ControlCommands.Prev" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="30,0,0,0" Style="{StaticResource ButtonCustom}">
<Border Width="50" Height="100" Background="{DynamicResource DarkOpacityBrush}" CornerRadius="4">
<Path Margin="16" Fill="White" Style="{StaticResource LeftPathStyle}"/>
</Border>
</Button>
<Button Command="interactivity:ControlCommands.Next" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,30,0" Style="{StaticResource ButtonCustom}">
<Border Width="50" Height="100" Background="{DynamicResource DarkOpacityBrush}" CornerRadius="4">
<Path Margin="16" Fill="White" Style="{StaticResource RightPathStyle}"/>
</Border>
</Button>
</controls:SimplePanel>
<StackPanel Name="PART_PanelPage" Orientation="Horizontal" VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="0,0,0,20"/>
</controls:SimplePanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!--<Style x:Key="CarouselListBoxItemStyle" BasedOn="{StaticResource ListBoxItemCustom}" TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="Height" Value="{Binding ActualHeight, RelativeSource={RelativeSource AncestorType=ItemsControl}}"/>
@@ -92,6 +176,6 @@
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Style>-->
</ResourceDictionary>