[ReactiveProperty]ObserveElementObservableProperty()の使い方がわからない
Q&A
Closed
お世話になっております。
解決したいこと
C# + WPFでベクターグラフィックスドローイングツールを開発しています。
※下にソースコードへの案内を記載しております。よろしければそちらを参照ください。
発生している問題・エラー
現在、レイヤー機能を実装しているところなのですが、レイヤーに含まれるItemを全て集めたReactivePropertyの作り方がわからなくて困っています。
各クラスの数量の関係は次の通りです。
DiagramViewModel 1対多 Layer
Layer 1対多 LayerItem
LayerItem 1対1 SelectableDesignerItemViewModelBase
DiagramViewModelで選択中のレイヤーのItemを追加・削除すると、選択中のLayerの中のLayerItem(SelectableDesignerItemViewModelBaseを含む)を追加・削除します。その変更に伴って、総量が変動するDiagramViewModel.AllItemsプロパティを書きました。しかし、DiagramViewModelクラスのLayerコレクションのLayerItemコレクションのSelectableDesignerItemViewModelBaseインスタンスを変更検知しながらReactiveCollectionを生成するコードの書き方が、Web上のどこを探しても見つかりませんでした。
今のところ、こじらせた書き方をしてしまっているのが原因かはわからないですが、ItemをDeleteキーで削除した後、画面上にItemが残ってしまいます。デバッグしたところ、DiagramViewModel.AllItemsプロパティの総量が正しく同期されていないようです。しかし、Itemの追加時は正しく同期されているようです。
上記の方法について、心当たりのある方はいらっしゃいますでしょうか。よろしければ教えてください。
public class DiagramViewModel : BindableBase, IDiagramViewModel, IDisposable
{
public DiagramViewModel()
{
:
AllItems = Layers.ObserveElementObservableProperty(x => x.AllItemsObservable)
.Select(x => x.Value.Value)
.ToReadOnlyReactiveCollection();
AllItems.ObserveAddChanged()
.Subscribe(x =>
{
Debug.WriteLine($"Added {x} into AllItems");
})
.AddTo(_CompositeDisposable);
AllItems.ObserveRemoveChanged()
.Subscribe(x =>
{
Debug.WriteLine($"Removed {x} from AllItems");
})
.AddTo(_CompositeDisposable);
:
}
:
public ReadOnlyReactiveCollection<SelectableDesignerItemViewModelBase> AllItems { get; }
:
}
public class Layer : BindableBase
{
:
public ReactiveCollection<LayerItem> Items { get; } = new ReactiveCollection<LayerItem>();
public IObservable<PropertyPack<LayerItem, bool>> Observable
{
get { return Items.ObserveElementObservableProperty(x => x.Observable); }
}
public IObservable<PropertyPack<LayerItem, SelectableDesignerItemViewModelBase>> AllItemsObservable
{
get { return Items.ObserveElementObservableProperty(x => x.AllItemsObservable); }
}
public Layer()
{
:
}
}
public class LayerItem : BindableBase, IDisposable
{
:
public ReactivePropertySlim<SelectableDesignerItemViewModelBase> Item { get; } = new ReactivePropertySlim<SelectableDesignerItemViewModelBase>();
public IObservable<bool> Observable
{
get { return Item.ObserveProperty(x => x.Value.IsSelected); }
}
public IObservable<SelectableDesignerItemViewModelBase> AllItemsObservable
{
get { return System.Reactive.Linq.Observable.Return(Item.Value); }
}
:
}
<UserControl
x:Class="boilersGraphics.UserControls.DiagramControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:attached="clr-namespace:boilersGraphics.AttachedProperties"
xmlns:behavior="clr-namespace:boilersGraphics.Views.Behaviors"
xmlns:control="clr-namespace:boilersGraphics.Controls"
xmlns:converter="clr-namespace:boilersGraphics.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:boilersGraphics="clr-namespace:boilersGraphics"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:local="clr-namespace:boilersGraphics.UserControls"
xmlns:helper="clr-namespace:boilersGraphics.Helpers"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:selector="clr-namespace:boilersGraphics.StyleSelectors"
xmlns:view="clr-namespace:boilersGraphics.Views"
xmlns:viewModel="clr-namespace:boilersGraphics.ViewModels"
d:DesignHeight="450"
d:DesignWidth="800"
Loaded="DesignerCanvas_Loaded"
mc:Ignorable="d">
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter" />
<converter:PointsToAngleConverter x:Key="PointsToAngleConverter" />
</UserControl.Resources>
<Border BorderBrush="LightGray" BorderThickness="1">
<Grid>
<ScrollViewer Name="DesignerScrollViewer"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseWheel">
<helper:EventToCommand Command="{Binding MouseWheelCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
<i:EventTrigger EventName="PreviewMouseDown">
<helper:EventToCommand Command="{Binding PreviewMouseDownCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
<i:EventTrigger EventName="PreviewMouseUp">
<helper:EventToCommand Command="{Binding PreviewMouseUpCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseMove">
<helper:EventToCommand Command="{Binding MouseMoveCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<helper:EventToCommand Command="{Binding MouseLeaveCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseEnter">
<helper:EventToCommand Command="{Binding MouseEnterCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
<ScrollViewer.Background>
<VisualBrush Stretch="None"
TileMode="Tile"
Viewport="0,0,16,16"
ViewportUnits="Absolute">
<VisualBrush.Visual>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="8" />
<ColumnDefinition Width="8" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="8" />
<RowDefinition Height="8" />
</Grid.RowDefinitions>
<Rectangle Grid.Row="0"
Grid.Column="0"
Fill="#EEE" />
<Rectangle Grid.Row="0"
Grid.Column="1"
Fill="#AAA" />
<Rectangle Grid.Row="1"
Grid.Column="0"
Fill="#AAA" />
<Rectangle Grid.Row="1"
Grid.Column="1"
Fill="#EEE" />
</Grid>
</VisualBrush.Visual>
</VisualBrush>
</ScrollViewer.Background>
<ItemsControl ItemContainerStyleSelector="{x:Static selector:DesignerItemsControlItemStyleSelector.Instance}"
ItemsSource="{Binding AllItems, UpdateSourceTrigger=PropertyChanged}"
Background="Transparent"
BorderBrush="Black"
BorderThickness="{Binding CanvasBorderThickness}">
<ItemsControl.Resources>
:
</ItemsControl.Resources>
:
</ScrollViewer>
<StackPanel Orientation="Vertical"
HorizontalAlignment="Right"
VerticalAlignment="Top">
<control:ZoomBox
x:Name="zoomBox"
Width="180"
Margin="0,5,25,0"
ScrollViewer="{Binding ElementName=DesignerScrollViewer}"
Visibility="{Binding EnableMiniMap.Value, Converter={StaticResource BoolToVisibilityConverter}}"/>
<control:Combine
x:Name="combine"
Width="180"
Margin="0,5,25,0" />
<control:Layers
x:Name="layers"
Width="180"
Margin="0,5,25,0" />
</StackPanel>
</Grid>
</Border>
</UserControl>
以下のGifアニメを見ると、アイテムを選択した後、Deleteキーを押すと、レイヤーウィンドウからはアイテムが削除されたことがわかりますが、画面上にはアイテムが残っています。
ソースコード
boiler's Graphics
https://github.com/dhq-boiler/boiler-s-Graphics
gitリポジトリ
https://github.com/dhq-boiler/boiler-s-Graphics.git
ブランチ:feature/Layer
コミット:78f32f7
何か私の見落とし、致命的な勘違いなど気づいたところがあれば、回答していただけると助かります。よろしくお願いいたします。