2014-03-18 7 views
2

WPF에서는 반응식 확장 기능이있는 마우스 이벤트를 사용하여 Click 이벤트처럼 작동하는 UIElement에 대한 관찰 가능을 만들 수 있기를 원합니다. 끌어서 놓기 동작을 만드는 데 사용하는 예제가 많이 있지만 단순한 클릭만으로는 아무 것도 찾을 수 없습니다.Reactive Extensions를 사용하여 시뮬레이션 UIElement 클릭

나는 그것이 MouseLeftButtonDown, MouseLeftButtonUp, MouseLeave 및 MouseEnter에서 관찰 가능 항목을 포함 할 것으로 예상하고 있습니다. 하지만 Merge, SelectMany, TakeUntil 또는 TakeWhile의 조합을 사용해야하는지 잘 모르겠습니다. 확장에 모든 것을 마무리하려고에서, 여기에 내가 지금까지 무엇을 가지고 :

+0

체크 아웃 : http://rxwiki.wikidot.com/101samples#toc50 나는'CombineLatest' 아주 잘 난 당신의 코드를 테스트하고 가까운 – Pellared

답변

3

은 다음

public static IDisposable GetClick(this UIElement item, Action clickAction) 
     { 
      var obs1 = Observable.FromEventPattern<MouseButtonEventHandler, MouseButtonEventArgs>(
        h => (s, e) => h(s, e), 
        h => item.MouseLeftButtonDown += h, 
        h => item.MouseLeftButtonDown -= h); 

      var obs2 = Observable.FromEventPattern<MouseButtonEventHandler, MouseButtonEventArgs>(
        h => (s, e) => h(s, e), 
        h => item.MouseLeftButtonUp += h, 
        h => item.MouseLeftButtonUp -= h); 

      var obs3 = Observable.FromEventPattern<MouseEventHandler, MouseEventArgs>(
        h => (s, e) => h(s, e), 
        h => item.MouseLeave += h, 
        h => item.MouseLeave -= h); 

      var obs4 = Observable.FromEventPattern<MouseEventHandler, MouseEventArgs>(
        h => (s, e) => h(s, e), 
        h => item.MouseEnter += h, 
        h => item.MouseEnter -= h); 

      var finalObs = ??? 

      return finalObs.Subscribe(x => clickAction.Invoke()); 

}가 작동하는 것 같다,하지만 난 그게 깔끔한 방법으로 그것을 할 수 있다고 생각 .

var click = mouseEnter 
    .SelectMany(_ => mouseDown.TakeUntil(mouseLeave)) 
    .SelectMany(_ => mouseUp.TakeUntil(mouseLeave).Take(1)); 

나는 ... obs1obs2mouseUp에, mouseDown에, clickfinalObs 이름을 변경 한

편집 : 추가 테이크 (1) 결함이 Enigmativity

EDIT (지적 해결하기 위해 2) :

다음은 내가 더 좋아하는 또 다른 해결책입니다.

당신은 모르기 때문에 mouseUp, mouseDown에 .Select(_ => "D")의 정의에 .Select(_ => "U")를 추가해야합니다 ...

var click = Observable.Merge(mouseDown, mouseUp, mouseLeave, mouseEnter) 
    .Scan((s, c) => c == "L" ? "" : s + c) // Create a string of the events, reset on mouseLeave 
    .Where(s => s.Length >= 2 && s.Substring(s.Length - 2) == "DU"); 

그것에 대해 생각하면,이 경우에 정확히 올바른 동작을 취득 불가능 경우 사용자 마우스 항목 위로 이동 한 다음 항목 밖으로 이동 한 다음 뒤로 이동하고 마우스를 위로 이동합니다. 이것은 항목을 넘지 않을 때는 마우스 업을하지 않기 때문에 마우스를 올리지 않았다고 확신 할 수 없으므로 밖에있는 동안 마우스를 아래로 두었 기 때문입니다.

+0

를 탐구 가치가 아니라 생각합니다. 첫 번째 클릭은 하나의'OnNext'를 제공하지만 다음 클릭은 두 번의 연속 된'OnNext' 호출을 제공합니다. 그 다음은 3 개를 제공합니다. 모든 클릭에 대해 'OnNext' 호출이 증가하는 산술 진행이 있습니다. – Enigmativity

+0

건배, 나는 그것을 테스트하지 않았다 –

+0

대답은 'Join', 'Window'및/또는 'Switch'가 포함될 것이라고 확신하지만, 내 뇌를 너무 많이 상하게한다. – Enigmativity

0

정확한 방법은 this.CaptureMousethis.ReleaseMouseCapture을 사용하여 허용 된 답변에서 마우스를 놓고 돌아 오는 감지와 관련된 몇 가지 문제를 해결합니다. ReactiveUI를 사용하여 이벤트를 바인딩하는 완전한 (테스트되지 않은) 솔루션입니다.

// Create a factory for capturing the mouse and and releasing it as an 
// IDisposable compatible with Observable.Using 
Func<IDisposable> captureDisposable =() => { 
     this.CaptureMouse(); 
     return Disposable.Create(()=>this.ReleaseMouseCapture()); 
}; 

// Capture the mouse and then release it on mouse up 
var up = Observable.Using 
    (captureDisposable 
    , capture => this.Events().PreviewMouseUp.Take(1) 
    ); 

// Create the click event 
var click = this.Events().PreviewMouseDown.Select(e=>up).Switch(); 
관련 문제