[英]How to properly filter the different actions that may result from a mouse event?
我正在設計CAD應用程序,不確定如何以干凈的方式設計鼠標事件的事件處理。
為簡單起見,假設我在用戶界面中有兩個按鈕:CreateSquare和CreateCircle。 當用戶單擊其中之一時,我希望應用程序等待畫布中的單擊,然后在用戶單擊后在所標識的位置創建正方形或圓形。
據我了解,有必要在畫布上監聽MouseDown事件,並在處理程序中編寫類似以下內容的內容:
bool CreatingSquaresMode;
bool CreatingCirclesMode;
private void ModelViewport_MouseDown(object sender, MouseButtonEventArgs e)
{
if (CreatingSquaresMode) {
// create square at selected position.
}
if (CreatingCirclesMode) {
// create circle at selected position.
}
}
但是,這似乎很臭,特別是因為我將有許多不同的create命令,但很快就會失去控制。 由於我希望將CreateSquare和CreateCircle按鈕綁定到命令,並且也不必擔心MouseDown事件,因此它也破壞了MVVM。
我考慮過的另一種方法是狀態機,在該狀態機中,我將確定應用程序的所有可能模式,並以更優雅的方式復制上述if-nest或switch-case。 仍然感覺這不是正確的解決方案,但是會更好。
第二種選擇-我認為這是正確的選擇-將在我的CreateSquare命令中以某種方式偵聽MouseDown事件:
private void CreateSquare() {
//do something here
//wait for user mouse input
//create square
}
但是我不知道那是否有可能。
處理這種情況的正確方法是什么? 我確定這里有一種設計模式應該可以為我提供幫助。
對於那些閱讀者來說,這就是我解決這個問題的方式。 上面的答案有助於確認我的想法。
首先,我創建了一個具有以下狀態和觸發器的狀態機(我使用Stateless ):
public enum States
{
Idle,
CreatingShape
}
public enum Triggers
{
CreateShape,
CancelCurrentAction
}
public class AppStateMachine : ObservableObject
{
public StateMachine<States, Triggers> _stateMachine = new StateMachine<States, Triggers>(States.Idle);
public AppStateMachine()
{
_stateMachine.Configure(States.Idle)
.Permit(Triggers.CreateShape, States.CreatingJunction)
.Ignore(Triggers.CancelCurrentAction);
_stateMachine.Configure(States.CreatingShape)
.Permit(Triggers.CancelCurrentAction, States.Idle)
.Ignore(Triggers.CreateShape);
}
然后,為了盡最大可能保留MVVM,我將UI按鈕綁定到“ SetCreationMode”命令,命令參數是要創建的形狀類型。 該命令如下所示:
XAML:
<RibbonButton x:Name="CreateSquare" Command="{Binding SetShapeCreationCommand}" CommandParameter="{Binding SquareShape}" Label="Create Square"/>
ViewModel:
private void SetShapeCreationMode(ShapeTypeEnum ShapeType)
{
SelectedShapeType = ShapeType;
_mainViewModel.AppState._stateMachine.Fire(Triggers.CreateShape);
}
這樣,當您按下按鈕時,App State Machine將觸發“ CreatingShape”狀態,並將“ SelectedShapeType”變量設置為您的形狀(在示例中為正方形)。
之后,您仍然必須將畫布單擊作為事件進行處理(我正在玩MVVMLight中的EventToCommand ,但是還沒有取得飛躍。)事件處理方法類似於:
private void ModelViewport_MouseDown(object sender, MouseButtonEventArgs e)
{
if (_mainViewModel.AppState.IsInState(States.CreatingShape))
{
// retrieve mouse position
// Execute command with retrieved position
_CreateShapeViewModel.CreateShapeGraphicallyCommand.Execute(Position);
}
}
這樣,您就可以在選定的鼠標位置上使用命令,而不必在ViewHandler中的EventHandler中擁有大量代碼。
這是處理它的最好方法嗎? 我不知道,但我希望能有所幫助。
解決問題的方法有很多,因此沒有“正確”的方法,但是肯定有更好的方法。 我提供了一個供您考慮的選項,但是我永遠不能說我(或其他任何人)的設計是“最佳”的,這取決於您自己決定。
在您的解決方案中,您將使用第一個按鈕來設置名為“ CreatingShapeMode”的屬性。 您是否只想在任何特定時間設置一種模式? 如果是這樣,請考慮使用一個枚舉
我認為您的MouseDown事件處理程序不應執行繪制形狀的工作(因為您指出此列表只會變得更大)。 取而代之的是,我將使用一些自定義形狀繪制類,這些類都從基本“ ObjectCreator”類型繼承。 第一次單擊將設置正確的類型,例如circleType或squareType; 在畫布上的第二次單擊(將觸發鼠標按下事件)將僅調用createShape方法; 它不需要任何if語句,因為它是知道如何繪制形狀的對象創建者。
這是一個控制台應用程序,具有最少的代碼量來演示我要說的內容。 顯然,它需要大量的調整才能適合您的問題。
using System;
namespace ConsoleApplication27
{
class Program
{
private static ObjectCreator creator;
static void Main(string[] args)
{
creator = new CircleCreator();//change this to change the "shape" you get
Console.ReadLine();
}
private static void YourMouseDownMethod()
{
creator.CreateObject();//no if statements required, the createObject method does the work
}
}
abstract class ObjectCreator
{
public abstract void CreateObject();
}
class SquareCreator:ObjectCreator
{
public override void CreateObject()
{
Console.WriteLine("Create Square");
}
}
class CircleCreator:ObjectCreator
{
public override void CreateObject()
{
Console.WriteLine("Create Circle");
}
}
}
您提到您希望將按鈕綁定到命令,您可以使用命令對象來設置正確的ObjectCreator類型。
class SetObjectCreatorCommand:ICommand
{
private readonly ObjectCreator _creator;
public SetObjectCreatorCommand(ObjectCreator creator)
{
_creator = creator;//for each shape type you would create an instance of this class
//e.g. pass in a circleCreator for circle shapes etc...
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
//Set the creator class here, you can bind a button's command property to a Command object
}
public event EventHandler CanExecuteChanged;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.