Added AutoMapper for BlockGroup to BlockGroupViewModel translation

This commit is contained in:
Ben 2015-06-18 21:08:44 +01:00
parent 8119018f33
commit c80d4825df
12 changed files with 299 additions and 140 deletions

View File

@ -1,8 +1,15 @@
using System.Linq;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Runtime.InteropServices.ComTypes;
using System.Windows;
using AutoMapper;
using Castle.MicroKernel.ModelBuilder.Inspectors;
using Castle.Windsor;
using Castle.Windsor.Installer;
using Filtration.Models;
using Filtration.Utilities;
using Filtration.ViewModels;
using Filtration.Views;
namespace Filtration
@ -24,18 +31,65 @@ namespace Filtration
_container.Install(FromAssembly.This());
// TODO: Find out how to parameterise this to map differently depending if ShowAdvanced is true or false.
//Mapper.CreateMap<ItemFilterBlockGroup, ItemFilterBlockGroupViewModel>()
// .ForMember(dest => dest.IsChecked,
// opts => opts.MapFrom(from => from.IsChecked))
// .ForMember(dest => dest.SourceBlockGroup,
// opts => opts.MapFrom(from => from));
//Mapper.CreateMap<ItemFilterBlockGroup, ItemFilterBlockGroupViewModel>()
// .ForMember(dest => dest.IsChecked,
// opts => opts.MapFrom(from => from.IsChecked))
// .ForMember(dest => dest.ChildGroups,
// opts => opts.ResolveUsing<ChildGroupsResolver>())
// .ForMember(dest => dest.SourceBlockGroup,
// opts => opts.MapFrom(from => from));
//.ForMember(dest => dest.ChildGroups,
// opts => opts.Condition(src => src.Advanced == false))
//opts => opts.ResolveUsing<ItemFilterBlockGroupChildGroupsResolver>())
//opts => opts.MapFrom(from => from.ChildGroups))
//Mapper.AssertConfigurationIsValid();
var mainWindow = _container.Resolve<IMainWindow>();
mainWindow.Show();
//String[] arguments = Environment.GetCommandLineArgs();
//if (arguments.GetLength(0) <= 1) return;
//if (!arguments[1].EndsWith(".filter")) return;
//var filePathFormMainArgs = arguments[1];
//mainWindow.OpenScriptFromCommandLineArgument(filePathFormMainArgs);
}
//private class ChildGroupsResolver : ValueResolver<ItemFilterBlockGroup, ItemFilterBlockGroupViewModel>
//{
// protected override ItemFilterBlockGroupViewModel ResolveCore(ItemFilterBlockGroup source)
// {
// return !source.Advanced ? Mapper.Map<ItemFilterBlockGroup, ItemFilterBlockGroupViewModel>(source) : null;
// }
//}
//private class ChildGroupsResolver :
// ValueResolver<List<ItemFilterBlockGroup>, ObservableCollection<ItemFilterBlockGroupViewModel>>
//{
// protected override ObservableCollection<ItemFilterBlockGroupViewModel> ResolveCore(List<ItemFilterBlockGroup> source)
// {
// var result = new ObservableCollection<ItemFilterBlockGroupViewModel>();
// if (source != null && source.Count > 0)
// {
// var filteredSource = source.Where(g => g.Advanced == false);
// foreach (var blockGroup in filteredSource)
// {
// result.Add(Mapper.Map<ItemFilterBlockGroup, ItemFilterBlockGroupViewModel>(blockGroup));
// }
// }
// return result;
// }
//}
protected override void OnExit(ExitEventArgs e)
{
_container.Dispose();

View File

@ -41,6 +41,12 @@
<ApplicationIcon>Resources\filtration.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="AutoMapper">
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.dll</HintPath>
</Reference>
<Reference Include="AutoMapper.Net4">
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.Net4.dll</HintPath>
</Reference>
<Reference Include="Castle.Core">
<HintPath>..\packages\Castle.Core.3.3.0\lib\net45\Castle.Core.dll</HintPath>
</Reference>
@ -175,6 +181,8 @@
<Compile Include="UserControls\ItemPreviewControl.xaml.cs">
<DependentUpon>ItemPreviewControl.xaml</DependentUpon>
</Compile>
<Compile Include="Utilities\AutoMapperHelpers.cs" />
<Compile Include="Utilities\BlockGroupMapper.cs" />
<Compile Include="Utilities\LineReader.cs" />
<Compile Include="ViewModels\AvalonDockWorkspaceViewModel.cs" />
<Compile Include="ViewModels\BlockGroupBrowserViewModel.cs" />
@ -182,6 +190,7 @@
<Compile Include="ViewModels\IDocument.cs" />
<Compile Include="ViewModels\IItemFilterScriptViewModelFactory.cs" />
<Compile Include="ViewModels\IItemFilterBlockViewModelFactory.cs" />
<Compile Include="ViewModels\ItemFilterBlockGroupViewModel.cs" />
<Compile Include="ViewModels\ItemFilterBlockViewModel.cs" />
<Compile Include="ViewModels\ItemFilterScriptViewModel.cs" />
<Compile Include="ViewModels\PaneViewModel.cs" />
@ -425,6 +434,7 @@
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(XamlSpyInstallPath)MSBuild\FirstFloor.XamlSpy.WPF.targets" Condition="'$(XamlSpyInstallPath)' != '' and '$(Configuration)' == 'DEBUG'" />
<Import Project="..\packages\AutoMapper.3.3.1\tools\AutoMapper.targets" Condition="Exists('..\packages\AutoMapper.3.3.1\tools\AutoMapper.targets')" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">

View File

@ -1,29 +1,44 @@
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using Filtration.Annotations;
using System.Collections.Generic;
namespace Filtration.Models
{
internal class ItemFilterBlockGroup : INotifyPropertyChanged
internal class ItemFilterBlockGroup
{
private bool? _isChecked;
private bool _reentrancyCheck;
private bool _isChecked;
public ItemFilterBlockGroup(string groupName, ItemFilterBlockGroup parent, bool advanced = false)
{
GroupName = groupName;
ParentGroup = parent;
Advanced = advanced;
ChildGroups = new ObservableCollection<ItemFilterBlockGroup>();
ChildGroups = new List<ItemFilterBlockGroup>();
}
public event EventHandler BlockGroupStatusChanged;
public string GroupName { get; private set; }
public ItemFilterBlockGroup ParentGroup { get; private set; }
public ObservableCollection<ItemFilterBlockGroup> ChildGroups { get; private set; }
public List<ItemFilterBlockGroup> ChildGroups { get; private set; }
public bool Advanced { get; private set; }
public bool IsChecked
{
get { return _isChecked; }
set
{
if (value != _isChecked)
{
_isChecked = value;
// Raise an event to let blocks that have this block group assigned that
// they might need to change their Action due to the block group status changing.
if (BlockGroupStatusChanged != null)
{
BlockGroupStatusChanged.Invoke(null, null);
}
}
}
}
public override string ToString()
{
@ -43,109 +58,5 @@ namespace Filtration.Models
return outputString;
}
public bool Advanced { get; private set; }
public bool? IsChecked
{
get
{
return _isChecked;
}
set
{
if (_isChecked != value)
{
if (_reentrancyCheck)
{
return;
}
_reentrancyCheck = true;
_isChecked = value;
UpdateCheckState();
OnPropertyChanged();
// Raise an event to let blocks that have this block group assigned that
// they might need to change their Action due to the block group status changing.
if (BlockGroupStatusChanged != null)
{
BlockGroupStatusChanged.Invoke(null, null);
}
_reentrancyCheck = false;
}
}
}
private void UpdateCheckState()
{
// update all children:
if (ChildGroups.Count != 0)
{
UpdateChildrenCheckState();
}
// update parent item
if (ParentGroup != null)
{
var parentIsChecked = ParentGroup.DetermineCheckState();
ParentGroup.IsChecked = parentIsChecked;
}
}
private void UpdateChildrenCheckState()
{
foreach (var childGroup in ChildGroups.Where(c => IsChecked != null && !c.Advanced))
{
childGroup.IsChecked = IsChecked;
}
}
private bool? DetermineCheckState()
{
var allChildrenChecked = ChildGroups.Count(x => x.IsChecked == true) == ChildGroups.Count;
if (allChildrenChecked)
{
return true;
}
var allChildrenUnchecked = ChildGroups.Count(x => x.IsChecked == false) == ChildGroups.Count;
if (allChildrenUnchecked)
{
return false;
}
return null;
}
public ItemFilterBlockGroup Search(Func<ItemFilterBlockGroup, bool> predicate)
{
// if node is a leaf
if (ChildGroups == null || ChildGroups.Count == 0)
{
return predicate(this) ? this : null;
}
var results = ChildGroups
.Select(i => i.Search(predicate))
.Where(i => i != null).ToList();
if (results.Any())
{
var result = (ItemFilterBlockGroup)MemberwiseClone();
result.ChildGroups = new ObservableCollection<ItemFilterBlockGroup>(results);
return result;
}
return null;
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}

View File

@ -433,6 +433,7 @@ namespace Filtration.Translators
private void AddStringListBlockItemToString(ref string targetString, StringListBlockItem blockItem)
{
var enumerable = blockItem.Items as IList<string> ?? blockItem.Items.ToList();
if (enumerable.Count > 0)
{

View File

@ -0,0 +1,31 @@
using System.Linq;
using Filtration.ViewModels;
namespace Filtration.Utilities
{
internal class AutoMapperHelpers
{
public static void ItemFilterBlockGroupViewModelPostMap(ItemFilterBlockGroupViewModel viewModel)
{
foreach (var childViewModel in viewModel.ChildGroups)
{
ItemFilterBlockGroupViewModelPostMap(childViewModel);
}
if (viewModel.ChildGroups.Count > 0)
{
if (viewModel.ChildGroups.All(g => g.IsChecked == true))
{
viewModel.IsChecked = true;
} else if (viewModel.ChildGroups.Any(g => g.IsChecked == true))
{
viewModel.IsChecked = null;
}
else
{
viewModel.IsChecked = false;
}
}
}
}
}

View File

@ -0,0 +1,47 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using AutoMapper;
using Filtration.Models;
using Filtration.ViewModels;
namespace Filtration.Utilities
{
internal interface IBlockGroupMapper
{
ObservableCollection<ItemFilterBlockGroupViewModel> MapBlockGroupsToViewModels(
ObservableCollection<ItemFilterBlockGroup> blockGroups, bool showAdvanced);
}
internal class BlockGroupMapper : IBlockGroupMapper
{
public ObservableCollection<ItemFilterBlockGroupViewModel> MapBlockGroupsToViewModels(
ObservableCollection<ItemFilterBlockGroup> blockGroups, bool showAdvanced)
{
Mapper.Reset();
if (showAdvanced)
{
Mapper.CreateMap<ItemFilterBlockGroup, ItemFilterBlockGroupViewModel>()
.ForMember(dest => dest.IsChecked,
opts => opts.MapFrom(from => from.IsChecked))
.ForMember(dest => dest.SourceBlockGroup,
opts => opts.MapFrom(from => from));
}
else
{
Mapper.CreateMap<ItemFilterBlockGroup, ItemFilterBlockGroupViewModel>()
.ForMember(dest => dest.IsChecked,
opts => opts.MapFrom(from => from.IsChecked))
.ForMember(dest => dest.ChildGroups,
opts => opts.MapFrom(from => from.ChildGroups.Where(c => c.Advanced == false)))
.ForMember(dest => dest.SourceBlockGroup,
opts => opts.MapFrom(from => from));
}
var mappedViewModels = Mapper.Map<ObservableCollection<ItemFilterBlockGroupViewModel>>(blockGroups);
AutoMapperHelpers.ItemFilterBlockGroupViewModelPostMap(mappedViewModels.First());
return mappedViewModels.First().ChildGroups;
}
}
}

View File

@ -0,0 +1,98 @@
using System.Collections.ObjectModel;
using System.Linq;
using Filtration.Models;
namespace Filtration.ViewModels
{
internal class ItemFilterBlockGroupViewModel : FiltrationViewModelBase
{
private bool? _isChecked;
private bool _reentrancyCheck;
private bool _postMapComplete;
public ItemFilterBlockGroupViewModel()
{
ChildGroups = new ObservableCollection<ItemFilterBlockGroupViewModel>();
}
public string GroupName { get; internal set; }
public ItemFilterBlockGroupViewModel ParentGroup { get; internal set; }
public ObservableCollection<ItemFilterBlockGroupViewModel> ChildGroups { get; internal set; }
public bool Advanced { get; internal set; }
public ItemFilterBlockGroup SourceBlockGroup { get; internal set; }
public bool? IsChecked
{
get
{
return _isChecked;
}
set
{
if (!_postMapComplete)
{
_isChecked = value;
_postMapComplete = true;
}
else
{
if (_isChecked != value)
{
if (_reentrancyCheck)
{
return;
}
_reentrancyCheck = true;
_isChecked = value;
UpdateCheckState();
RaisePropertyChanged();
SourceBlockGroup.IsChecked = value ?? false;
_reentrancyCheck = false;
}
}
}
}
private void UpdateCheckState()
{
// update all children:
if (ChildGroups.Count != 0)
{
UpdateChildrenCheckState();
}
// update parent item
if (ParentGroup != null)
{
var parentIsChecked = ParentGroup.DetermineCheckState();
ParentGroup.IsChecked = parentIsChecked;
}
}
private void UpdateChildrenCheckState()
{
foreach (var childGroup in ChildGroups.Where(c => IsChecked != null))
{
childGroup.IsChecked = IsChecked;
}
}
private bool? DetermineCheckState()
{
var allChildrenChecked = ChildGroups.Count(x => x.IsChecked == true) == ChildGroups.Count;
if (allChildrenChecked)
{
return true;
}
var allChildrenUnchecked = ChildGroups.Count(x => x.IsChecked == false) == ChildGroups.Count;
if (allChildrenUnchecked)
{
return false;
}
return null;
}
}
}

View File

@ -8,7 +8,6 @@ using System.Windows;
using System.Windows.Data;
using System.Windows.Forms;
using Castle.Core.Internal;
using Filtration.Enums;
using Filtration.Models;
using Filtration.Services;
using Filtration.Translators;
@ -24,7 +23,7 @@ namespace Filtration.ViewModels
ItemFilterScript Script { get; }
IItemFilterBlockViewModel SelectedBlockViewModel { get; set; }
IItemFilterBlockViewModel SectionBrowserSelectedBlockViewModel { get; set; }
IEnumerable<ItemFilterBlockGroup> BlockGroups { get; }
ObservableCollection<ItemFilterBlockGroup> BlockGroups { get; }
IEnumerable<IItemFilterBlockViewModel> ItemFilterSectionViewModels { get; }
Predicate<IItemFilterBlockViewModel> BlockFilterPredicate { get; set; }
bool IsDirty { get; }
@ -111,7 +110,6 @@ namespace Filtration.ViewModels
_itemFilterBlockViewModelsCollectionView.Filter = null;
}
return _itemFilterBlockViewModels;
}
}
@ -131,8 +129,6 @@ namespace Filtration.ViewModels
}
}
public ObservableCollection<IItemFilterBlockViewModel> DisplayedItemFilterBlockViewModels { get; private set; }
public IEnumerable<IItemFilterBlockViewModel> ItemFilterSectionViewModels
{
get { return ItemFilterBlockViewModels.Where(b => b.Block.GetType() == typeof (ItemFilterSection)); }
@ -187,7 +183,7 @@ namespace Filtration.ViewModels
public ItemFilterScript Script { get; private set; }
public IEnumerable<ItemFilterBlockGroup> BlockGroups
public ObservableCollection<ItemFilterBlockGroup> BlockGroups
{
get { return Script.ItemFilterBlockGroups; }
}
@ -251,6 +247,12 @@ namespace Filtration.ViewModels
ItemFilterBlockViewModels.Add(vm);
}
//BlockGroupViewModels =_blockGroupMapper.MapBlockGroupsToViewModels(Script.ItemFilterBlockGroups, false);
// Necessary to perform the AfterMap here instead of in the AutoMapper config due to the mapping being
// performed on a collection, but the postmap needs to be performed from the root BlockGroup.
//AutoMapperHelpers.ItemFilterBlockGroupViewModelPostMap(BlockGroupViewModels.First());
_filenameIsFake = newScript;
if (newScript)

View File

@ -61,7 +61,7 @@
</ToolBar>
<ToolBar>
<Button ToolTip="Clear Filter" Command="{Binding ClearFilterCommand}" Content="{StaticResource ClearFilterIcon}" />
<!--<ToggleButton ToolTip="Show Advanced Block Groups" Command="{Binding ToggleShowAdvancedCommand}" CommandParameter="{Binding Path=IsChecked, RelativeSource={RelativeSource Self}}" Content="{StaticResource ShowAdvancedIcon}" />-->
<ToggleButton ToolTip="Show Advanced Block Groups" Command="{Binding ToggleShowAdvancedCommand}" CommandParameter="{Binding Path=IsChecked, RelativeSource={RelativeSource Self}}" Content="{StaticResource ShowAdvancedIcon}" />
</ToolBar>
</ToolBarTray>
<userControls:AutoScrollingListBox ItemsSource="{Binding ItemFilterBlockViewModels}"

View File

@ -3,7 +3,6 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:models="clr-namespace:Filtration.Models"
xmlns:viewModels="clr-namespace:Filtration.ViewModels"
xmlns:converters="clr-namespace:Filtration.Converters"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
@ -13,7 +12,6 @@
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<converters:BlockGroupAdvancedColorConverter x:Key="BlockGroupAdvancedColorConverter" />
<converters:BlockGroupVisibilityConverter x:Key="BlockGroupVisibilityConverter" />
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
@ -24,12 +22,12 @@
<Button Height="20" Command="{Binding FilterToSelectedBlockGroupCommand}" Content="{StaticResource FilterIcon}" ToolTip="Filter to Selected Block Group" />
</ToolBar>
<TreeView Grid.Row="1" ItemsSource="{Binding BlockGroups}" Name="TreeView">
<TreeView Grid.Row="1" ItemsSource="{Binding BlockGroupViewModels}" Name="TreeView">
<i:Interaction.Behaviors>
<behaviors:BindableSelectedItemBehavior SelectedItem="{Binding SelectedBlockGroup, Mode=OneWayToSource}" />
<behaviors:BindableSelectedItemBehavior SelectedItem="{Binding SelectedBlockGroupViewModel, Mode=OneWayToSource}" />
</i:Interaction.Behaviors>
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type models:ItemFilterBlockGroup}" ItemsSource="{Binding ChildGroups}">
<HierarchicalDataTemplate DataType="{x:Type viewModels:ItemFilterBlockGroupViewModel}" ItemsSource="{Binding ChildGroups}">
<WrapPanel>
<CheckBox IsThreeState="True" IsChecked="{Binding IsChecked}" Click="BlockGroupCheckBox_Clicked" />
<TextBlock Text="{Binding GroupName}" Foreground="{Binding Advanced, Converter={StaticResource BlockGroupAdvancedColorConverter}}" />

View File

@ -2,6 +2,7 @@
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;
using Filtration.Services;
using Filtration.Utilities;
namespace Filtration.WindsorInstallers
{
@ -23,6 +24,11 @@ namespace Filtration.WindsorInstallers
Component.For<IStaticDataService>()
.ImplementedBy<StaticDataService>()
.LifeStyle.Singleton);
container.Register(
Component.For<IBlockGroupMapper>()
.ImplementedBy<BlockGroupMapper>()
.LifeStyle.Singleton);
}
}
}

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="AutoMapper" version="3.3.1" targetFramework="net451" />
<package id="AvalonDock" version="2.0.2000" targetFramework="net451" />
<package id="Castle.Core" version="3.3.0" targetFramework="net451" />
<package id="Castle.Windsor" version="3.3.0" targetFramework="net451" />