rewrite ObservableCollectionViewModel
This commit is contained in:
@@ -52,13 +52,16 @@ public partial class App :
|
|||||||
{
|
{
|
||||||
static IEnumerable<WidgetContainerViewModel> Resolve(IServiceProvider services)
|
static IEnumerable<WidgetContainerViewModel> Resolve(IServiceProvider services)
|
||||||
{
|
{
|
||||||
|
int index = 0;
|
||||||
foreach (IWidgetContext widgetContext in services.GetServices<IWidgetContext>())
|
foreach (IWidgetContext widgetContext in services.GetServices<IWidgetContext>())
|
||||||
{
|
{
|
||||||
if (widgetContext.ServiceProvider.GetServices<IWidgetViewModel>() is
|
if (widgetContext.ServiceProvider.GetServices<IWidgetViewModel>() is
|
||||||
IEnumerable<IWidgetViewModel> viewModels)
|
IEnumerable<IWidgetViewModel> viewModels)
|
||||||
{
|
{
|
||||||
yield return (WidgetContainerViewModel)ActivatorUtilities.CreateInstance(widgetContext.ServiceProvider,
|
yield return (WidgetContainerViewModel)ActivatorUtilities.CreateInstance(widgetContext.ServiceProvider,
|
||||||
typeof(WidgetContainerViewModel), viewModels);
|
typeof(WidgetContainerViewModel), viewModels, index % 2 == 0);
|
||||||
|
|
||||||
|
index++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,24 @@
|
|||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:ui="using:Hyperbar.Windows.UI">
|
xmlns:ui="using:Hyperbar.Windows.UI">
|
||||||
<ItemsControl ItemTemplateSelector="{Binding Converter={ui:DataTemplateConverter}}" ItemsSource="{Binding}">
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Rectangle
|
||||||
|
Width="1"
|
||||||
|
Margin="6,0,6,0"
|
||||||
|
Fill="Red" />
|
||||||
|
<ItemsControl
|
||||||
|
Grid.Column="1"
|
||||||
|
ItemTemplateSelector="{Binding Converter={ui:DataTemplateConverter}}"
|
||||||
|
ItemsSource="{Binding}">
|
||||||
<ItemsControl.ItemsPanel>
|
<ItemsControl.ItemsPanel>
|
||||||
<ItemsPanelTemplate>
|
<ItemsPanelTemplate>
|
||||||
<StackPanel Orientation="Horizontal" />
|
<StackPanel Orientation="Horizontal" />
|
||||||
</ItemsPanelTemplate>
|
</ItemsPanelTemplate>
|
||||||
</ItemsControl.ItemsPanel>
|
</ItemsControl.ItemsPanel>
|
||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|||||||
@@ -1,14 +1,21 @@
|
|||||||
using System.Collections.ObjectModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
|
||||||
namespace Hyperbar;
|
namespace Hyperbar;
|
||||||
|
|
||||||
|
public partial class ObservableCollectionViewModel<TItem> :
|
||||||
public class ObservableCollectionViewModel<TItem> :
|
ObservableObject,
|
||||||
ObservableCollection<TItem>,
|
IList<TItem>,
|
||||||
|
IList,
|
||||||
|
IReadOnlyList<TItem>,
|
||||||
|
INotifyCollectionChanged,
|
||||||
INotificationHandler<CollectionChanged<IEnumerable<TItem>>>
|
INotificationHandler<CollectionChanged<IEnumerable<TItem>>>
|
||||||
{
|
{
|
||||||
private readonly IServiceFactory serviceFactory;
|
public ObservableCollection<TItem> collection = [];
|
||||||
private readonly SynchronizationContext? context;
|
private readonly SynchronizationContext? context;
|
||||||
|
private readonly IServiceFactory serviceFactory;
|
||||||
|
|
||||||
public ObservableCollectionViewModel(IServiceFactory serviceFactory,
|
public ObservableCollectionViewModel(IServiceFactory serviceFactory,
|
||||||
IMediator mediator)
|
IMediator mediator)
|
||||||
@@ -17,6 +24,8 @@ public class ObservableCollectionViewModel<TItem> :
|
|||||||
|
|
||||||
this.serviceFactory = serviceFactory;
|
this.serviceFactory = serviceFactory;
|
||||||
mediator.Subscribe(this);
|
mediator.Subscribe(this);
|
||||||
|
|
||||||
|
collection.CollectionChanged += OnCollectionChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObservableCollectionViewModel(IServiceFactory serviceFactory,
|
public ObservableCollectionViewModel(IServiceFactory serviceFactory,
|
||||||
@@ -28,9 +37,56 @@ public class ObservableCollectionViewModel<TItem> :
|
|||||||
this.serviceFactory = serviceFactory;
|
this.serviceFactory = serviceFactory;
|
||||||
mediator.Subscribe(this);
|
mediator.Subscribe(this);
|
||||||
|
|
||||||
|
collection.CollectionChanged += OnCollectionChanged;
|
||||||
|
|
||||||
AddRange(items);
|
AddRange(items);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public event NotifyCollectionChangedEventHandler? CollectionChanged;
|
||||||
|
|
||||||
|
public int Count => collection.Count;
|
||||||
|
|
||||||
|
bool IList.IsFixedSize => false;
|
||||||
|
|
||||||
|
bool ICollection<TItem>.IsReadOnly => false;
|
||||||
|
|
||||||
|
bool IList.IsReadOnly => false;
|
||||||
|
|
||||||
|
bool ICollection.IsSynchronized => false;
|
||||||
|
|
||||||
|
object ICollection.SyncRoot => this;
|
||||||
|
|
||||||
|
protected IList<TItem> Items => collection;
|
||||||
|
|
||||||
|
public TItem this[int index]
|
||||||
|
{
|
||||||
|
get => collection[index];
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetItem(index, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object? IList.this[int index]
|
||||||
|
{
|
||||||
|
get => collection[index];
|
||||||
|
set
|
||||||
|
{
|
||||||
|
TItem? item = default;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
item = (TItem)value!;
|
||||||
|
}
|
||||||
|
catch (InvalidCastException)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
this[index] = item!;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public TItem Add()
|
public TItem Add()
|
||||||
{
|
{
|
||||||
TItem? item = serviceFactory.Create<TItem>();
|
TItem? item = serviceFactory.Create<TItem>();
|
||||||
@@ -58,6 +114,29 @@ public class ObservableCollectionViewModel<TItem> :
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Add(TItem item)
|
||||||
|
{
|
||||||
|
int index = collection.Count;
|
||||||
|
InsertItem(index, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
int IList.Add(object? value)
|
||||||
|
{
|
||||||
|
TItem? item = default;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
item = (TItem)value!;
|
||||||
|
}
|
||||||
|
catch (InvalidCastException)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Add(item!);
|
||||||
|
return Count - 1;
|
||||||
|
}
|
||||||
|
|
||||||
public void AddRange(IEnumerable<TItem> items)
|
public void AddRange(IEnumerable<TItem> items)
|
||||||
{
|
{
|
||||||
foreach (TItem? item in items)
|
foreach (TItem? item in items)
|
||||||
@@ -65,6 +144,19 @@ public class ObservableCollectionViewModel<TItem> :
|
|||||||
context?.Post(state => Add(item), null);
|
context?.Post(state => Add(item), null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public void Clear() => ClearItems();
|
||||||
|
|
||||||
|
public bool Contains(TItem item) => collection.Contains(item);
|
||||||
|
|
||||||
|
bool IList.Contains(object? value) => IsCompatibleObject(value) && Contains((TItem)value!);
|
||||||
|
|
||||||
|
public void CopyTo(TItem[] array, int index) => collection.CopyTo(array, index);
|
||||||
|
|
||||||
|
void ICollection.CopyTo(Array array, int index) => collection.CopyTo((TItem[])array, index);
|
||||||
|
|
||||||
|
public IEnumerator<TItem> GetEnumerator() => collection.GetEnumerator();
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)collection).GetEnumerator();
|
||||||
|
|
||||||
public ValueTask Handle(CollectionChanged<IEnumerable<TItem>> notification,
|
public ValueTask Handle(CollectionChanged<IEnumerable<TItem>> notification,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
@@ -74,6 +166,55 @@ public class ObservableCollectionViewModel<TItem> :
|
|||||||
|
|
||||||
return ValueTask.CompletedTask;
|
return ValueTask.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int IndexOf(TItem item) => collection.IndexOf(item);
|
||||||
|
|
||||||
|
int IList.IndexOf(object? value) => IsCompatibleObject(value) ? IndexOf((TItem)value!) : -1;
|
||||||
|
|
||||||
|
public void Insert(int index, TItem item) => InsertItem(index, item);
|
||||||
|
|
||||||
|
void IList.Insert(int index, object? value)
|
||||||
|
{
|
||||||
|
if (value is TItem item)
|
||||||
|
{
|
||||||
|
Insert(index, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Remove(TItem item)
|
||||||
|
{
|
||||||
|
int index = collection.IndexOf(item);
|
||||||
|
if (index < 0) return false;
|
||||||
|
RemoveItem(index);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IList.Remove(object? value)
|
||||||
|
{
|
||||||
|
if (IsCompatibleObject(value))
|
||||||
|
{
|
||||||
|
Remove((TItem)value!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void RemoveAt(int index) => RemoveItem(index);
|
||||||
|
|
||||||
|
protected virtual void ClearItems() => collection.Clear();
|
||||||
|
|
||||||
|
protected virtual void InsertItem(int index, TItem value)
|
||||||
|
{
|
||||||
|
if (value is TItem item)
|
||||||
|
{
|
||||||
|
collection.Insert(index, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void RemoveItem(int index) => collection.RemoveAt(index);
|
||||||
|
|
||||||
|
protected virtual void SetItem(int index, TItem item) => collection[index] = item;
|
||||||
|
|
||||||
|
private static bool IsCompatibleObject(object? value) => (value is TItem) || (value == null && default(TItem) == null);
|
||||||
|
|
||||||
|
private void OnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs args) => CollectionChanged?.Invoke(this, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ObservableCollectionViewModel(IServiceFactory serviceFactory, IMediator mediator) :
|
public class ObservableCollectionViewModel(IServiceFactory serviceFactory, IMediator mediator) :
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
|
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
|
||||||
namespace Hyperbar;
|
namespace Hyperbar;
|
||||||
|
|
||||||
public class WidgetContainerViewModel(ITemplateFactory templateFactory,
|
public partial class WidgetContainerViewModel(ITemplateFactory templateFactory,
|
||||||
IServiceFactory serviceFactory,
|
IServiceFactory serviceFactory,
|
||||||
IMediator mediator,
|
IMediator mediator,
|
||||||
IEnumerable<IWidgetViewModel> items) :
|
IEnumerable<IWidgetViewModel> items,
|
||||||
|
bool alternate) :
|
||||||
ObservableCollectionViewModel<IWidgetViewModel>(serviceFactory, mediator, items),
|
ObservableCollectionViewModel<IWidgetViewModel>(serviceFactory, mediator, items),
|
||||||
ITemplatedViewModel
|
ITemplatedViewModel
|
||||||
{
|
{
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool alternate = alternate;
|
||||||
|
|
||||||
public ITemplateFactory TemplateFactory => templateFactory;
|
public ITemplateFactory TemplateFactory => templateFactory;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user