c# 윈폼 UI

윈폼에서 엘리베이터가

Move(); // 엘레베이터 움직임 함수
UIMove() // 실제 윈폼 UI 움직임 함수

Move가 끝나면 UIMove 로 ui가 움직입니다 이런식으로 동작해도 되나요?

아니면 두개가 동시에 작동해야하나요?

저렇게하면 코드상에는 층수에 도착해도 ui는 움직이고 있는데 어떻게 처리해야할가요?

엘리베이터의 실제 움직임과 UI 상 표시를 일치시키려면

UIMove() 가 아니라 뭔가 실제 엘리베이터의 car 위치를 센서로 받아서 처리해야하지 않을까요?

갠적인 경험으루…

엘베에서 갇힌 적이 있었는데요…

14층에서 출발해서 1층으로 내려가는 엘리베이터였는데
뭔가 걸리는 듯한 움직임을 보이다 결국 멈춰 섰지만
car 내부의 현재 층 표시는 계속 움직여서 1층으로 표시되더라구요.
같이 갇힌 사람들 모두 1층에서 멈췄다고 생각해 안심했지만
하지만 실제로 7층에 걸려서 매달려 있었어요…
누군가 갇힌 사람 지인이 전화해서

야 너 7층에서 멈춰서 매달려 있어!

라고 알려준 다음에야 다들 공황이 찾아왔었죠…
1층 디스플레이에서는 정상적으로 표시되었나 보더라구요.

30분 가까이 매달려 있었슴다. 거의 20m 공중에서…=ㅅ=;
(그 뒤로 한 동안 엘리베이터를 못 탔…)

실제 엘리베이터의 위치와 UI 표시를 일치하려면 실제 값을 받아서 처리해야할 거 같네요.

그게 아니라면 UI 표시는 별 의미 없을 듯 합니다.

1 Like

vm에 floor 값이 있다고 하면

xaml에서 converter를 사용해 표현하는…

근데 읽고 보니 윈폼이군요.

윈폼도 요즘 바인딩 되는걸로 들었는데

2 Likes

UI 스레드에서 일정 시간 간격으로 현재 엘레베이터 움직임 상태를 체크해서 연동하는게 편할듯 하네요. Move에서는 층마다 그 변수를 바꿔주고요.

Async in 4.5: Enabling Progress and Cancellation in Async APIs - .NET Blog

1 Like

보통 엘레베이터 카(?) 대게 상부 또는 하단 쪽에 층 표시 센서가 있어서
각 층마다 센서 인식으로 인해 층 표시를 합니다.

센서 위치는 엘레베이터 제작사 자유입니다.

단편적인 예로 이해를 도움을 드리자면 체감상 현재 층에 위, 아래에 있지만 층이 변하지 않고 거의 도착했을 때 또는 해당 층에 2/3정도 층이 변화가 생깁니다.(이것또한 제작사 마음…)

실제 엘레베이터 프로토콜를 보시면 기본적인 베이스로
다음 내용은 포함되어있습니다.

상태 : 움직임, 정지
방향 : 위, 아래
현재 층 수 : 
운전상태 : 비상 운전, 화재운전, 정상 운전
1 Like

이 상태를 기준으로 코드를 짠다면,

class MoveExam
{
    public async Task InitiateMove(int to, Action<ElevatorStatus> moveUi)
    {
        var progress = new Progress<ElevatorStatus>(moveUi);
        try { 
            await Move(to, progress); 
        } catch (MoveEndException) { 
            Console.WriteLine("Move ends. See you again."); 
        } catch (Exception) { throw; }
    }
    async static Task Move(int to, IProgress<ElevatorStatus> progress)
    {
        var current = new ElevatorStatus(1, Moving.None, Mode.Normal);
        var target = new ElevatorStatus(to, Moving.None, Mode.Normal);

        DateTime start = DateTime.Now;
        progress.Report(current);
        while(current.Mode == Mode.Normal && current != target)
        {            
            await Task.Delay(100);
            var now = DateTime.Now;
            // Too frequent reporting will clock subscriber.
            if((now - start) >= TimeSpan.FromSeconds(1)) 
            {
                start = now;
                // immitate calling status checkers.
                var floor = current.Floor + 1;
                var moving = floor == to ? Moving.None
                    : floor < current.Floor ? Moving.Down
                    : Moving.Up;
                var mode = Mode.Normal;
                current = new ElevatorStatus(floor, moving, mode);
                progress.Report(current);
            }
        }
        // Handle abnormal modes
        // if(current.Mode != Mode.Normal) {  }
        throw new MoveEndException();
    }
}
record ElevatorStatus(int Floor, Moving Moving, Mode Mode);
enum Moving { None=0, Up, Down }
enum Mode { Normal = 0, Emergency, Fire }
class MoveEndException : Exception {}

실행

await new MoveExam().InitiateMove(5, status => Console.WriteLine(status));
Console.ReadKey();

결과

ElevatorStatus { Floor = 1, Moving = None, Mode = Normal }
ElevatorStatus { Floor = 2, Moving = Up, Mode = Normal }
ElevatorStatus { Floor = 3, Moving = Up, Mode = Normal }
ElevatorStatus { Floor = 4, Moving = Up, Mode = Normal }
ElevatorStatus { Floor = 5, Moving = None, Mode = Normal }
Move ends. See you again.

2 Likes