public SelectRectangleViewModel() { MouseDownPoint = new ReactivePropertySlim <Point>(mode: ReactivePropertyMode.None).AddTo(CompositeDisposable); MouseUpPoint = new ReactivePropertySlim <Point>(mode: ReactivePropertyMode.None).AddTo(CompositeDisposable); MouseMovePoint = new ReactivePropertySlim <Point>().AddTo(CompositeDisposable); ViewImageSize = new ReactivePropertySlim <Size>().AddTo(CompositeDisposable); IsFinishedSelectingRectangle = new ReactivePropertySlim <bool>().AddTo(CompositeDisposable); SelectedRectangle = new ReactivePropertySlim <Rect>().AddTo(CompositeDisposable); FixedRectangle = new ReactivePropertySlim <Rect>().AddTo(CompositeDisposable); // マウス操作中に移動量を流す + 操作完了時に枠位置を通知する MouseMovePoint .Select(movePoint => (startPoint: MouseDownPoint.Value, latestPoint: movePoint)) .SkipUntil(MouseDownPoint.ToUnit()) .TakeUntil(MouseUpPoint.ToUnit()) .Finally(() => { var(startPoint, latestPoint) = (MouseDownPoint.Value, MouseUpPoint.Value); if (startPoint == latestPoint) { return; } // 実画像の座標系に変換 var viewRect = ClipRectangle(new Rect(startPoint, latestPoint), ViewImageSize.Value); var imagePixelSize = new Size(MyImage.PixelWidth, MyImage.PixelHeight); var imagePixelRect = ConvertCoordinate(viewRect, ViewImageSize.Value, imagePixelSize); FixedRectangle.Value = imagePixelRect; IsFinishedSelectingRectangle.Value = true; }) .Repeat() .Subscribe(x => { SelectedRectangle.Value = ClipRectangle(new Rect(x.startPoint, x.latestPoint), ViewImageSize.Value); IsFinishedSelectingRectangle.Value = false; }) .AddTo(CompositeDisposable); // Viewのサイズ変更に枠サイズを追従 ViewImageSize .Pairwise() .Where(x => x.OldItem.Width != 0 && x.OldItem.Height != 0) .Select(x => (X: x.NewItem.Width / x.OldItem.Width, Y: x.NewItem.Height / x.OldItem.Height)) .Subscribe(ratio => SelectedRectangle.Value = MultipleRectangle(SelectedRectangle.Value, ratio.X, ratio.Y)) .AddTo(CompositeDisposable); }