在我當前的 C#/WPF 專案中,我使用切換按鈕Interaction.Triggers來啟動和停止測量,它按預期作業。您按下開始按鈕,它開始測量,按下停止按鈕,它停止并重置屬性,以便您可以再次執行此操作。
GUI 中的程序如下所示:
XAML 代碼:
<ToggleButton x:Name="ButtonMeasurementConnect"
Grid.Row="5" Grid.Column="3"
VerticalAlignment="Center"
Content="{Binding ButtonDataAcquisitionName}"
IsChecked="{Binding IsDataAcquisitionActivated, Mode=TwoWay}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<i:InvokeCommandAction Command="{Binding StartMeasurementCommand}"/>
</i:EventTrigger>
<i:EventTrigger EventName="Unchecked">
<i:InvokeCommandAction Command="{Binding StopMeasurementCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ToggleButton>
現在我添加了設定計時器的選項,以便程式在所需時間后自動停止測量,如本例所示。
您可以看到,當我單擊開始按鈕時,計時器在 1 秒處停止,開始按鈕名稱屬性再次正確重置為“開始”而不是“停止”。
最后是問題所在:如果我想重復它,我必須按兩次“開始”按鈕。第一次再次按下只會導致呼叫 S topMeasurementCommand。
我如何告訴切換按鈕它應該StartMeasurementCommand在下次在后面的代碼中使用時重置為使用系結,而不是手動按下按鈕?
編輯:這是視圖模型中的代碼,首先是對命令的明顯處理:
StartMeasurementCommand = new DelegateCommand(OnStartMeasurementExecute);
StopMeasurementCommand = new DelegateCommand(OnStopMeasurementExecute);
這里OnStopMeasurementExecute:
try
{
if (stopWatch.IsRunning)
{
stopWatch.Stop();
}
_receivingDataLock = true;
// Stop writing/consuming and displaying
_sourceDisplay.Cancel();
if (IsRecordingRequested)
{
_sourceWriter.Cancel();
} else
{
_sourceConsumer.Cancel();
}
// Sending stop command to LCA
_dataAcquisition.StopDataAcquisition();
// Flags
ButtonRecordingVisibility = Visibility.Hidden;
IsDataAcquisitionActivated = false;
IsDataAcquisitionDeactivated = true;
ButtonDataAcquisitionName = "Start";
if (IsRecordingRequested)
{
StatusMessage = "Recording stopped after " CurrentTime;
}
else
{
StatusMessage = "Live data stopped after " CurrentTime;
}
if (IsRecordingRequested) _recordedDataFile.Close();
}
catch (Exception e)
{
Console.WriteLine("Exception in OnStopMeasurementExecute: " e.Message);
}
如果設定了計時器,它也會被計時器函式呼叫:
void Stopwatch_Tick(object sender, EventArgs e)
{
if (stopWatch.IsRunning)
{
TimeSpan ts = stopWatch.Elapsed;
CurrentTime = String.Format("{0:00}:{1:00}:{2:00}", ts.Minutes, ts.Seconds, ts.Milliseconds / 10);
if ((IsTimerActivated) && (MeasureTime>0)) {
if (ts.Seconds >= MeasureTime) OnStopMeasurementExecute();
}
}
}
uj5u.com熱心網友回復:
您的問題的原因IsDataAcquisitionActivated是在視圖模型中重置,但您沒有引發屬性更改通知。因此系結不會被通知更改并保持其舊值,即false. 這意味著,雖然按鈕上的文本發生了變化,但它仍然處于Unchecked狀態,導致StopMeasurementCommand被執行。
我注意到
OnPropertyChanged();!IsDataAcquisitionActivated[...] 我記得為什么它被注釋掉StopMeasurement了
正確的。讓我們回顧一下此場景中的事件順序以找出問題所在。
- 被
ToggleButton點擊。 - 測量開始,
IsDataAcquisitionActivated設定為true從ToggleButton。 - 引發屬性更改通知。
- 將
ToggleButton其狀態更改為Checked。 - 引發事件
Checked并呼叫StartMeasurementCommand啟動計時器。 - 計時器用完并呼叫
OnStopMeasurementExecute. (第一次)。 - 該方法設定
IsDataAcquisitionActivated為false。 - 引發屬性更改通知。
- 將
ToggleButton其狀態更改為Unchecked。 Unchecked引發事件并呼叫StopMeasurementCommand(第二次)。- ...等等。
根本問題是在雙向系結狀態的同時依賴這里的事件。IsChecked如果沒有針對它的要求,那么做其中一個或另一個要容易得多。
在事件序列中,您會看到計時器OnStopMeasurementExecute通過執行它并間接觸發OnStopMeasurementExecute來自ToggleButton. 如果你不呼叫方法,而只設定IsDataAcquisitionActivated屬性,它只會被呼叫一次。
if (ts.Seconds >= MeasureTime) IsDataAcquisitionActivated = false;
這不需要對您的代碼進行太多調整,盡管我更喜歡一種不將事件連接到命令的方法,因為它更難理解和跟蹤。
這里有兩種使用顯式事件到命令系結的替代方法。
一、統一指揮治國
ToggleButton唯一關心IsDataAcquisitionActivated顯示正確狀態的屬性Checked或Unchecked。它不必設定 state,所以讓命令處理它。讓我們使用單向系結,因為視圖模型是這里的真實來源。然后讓我們將兩個單獨的命令合二為一,ToggleMeasurementCommand.
<ToggleButton x:Name="ButtonMeasurementConnect"
Grid.Row="5" Grid.Column="3"
VerticalAlignment="Center"
Content="{Binding ButtonDataAcquisitionName}"
IsChecked="{Binding IsDataAcquisitionActivated, Mode=OneWay}"
Command="{Binding ToggleMeasurementCommand}"/>
現在ToggleMeasurementCommand僅根據IsDataAcquisitionActivated屬性委托給 start 或 stop 方法。
ToggleMeasurementCommand = new DelegateCommand(OnToggleMeasurementExecute);
private void OnToggleMeasurementExecute()
{
if (IsDataAcquisitionActivated)
OnStartMeasurementExecute();
else
OnStopMeasurementExecute();
}
調整 start 和 stop 方法以設定正確的狀態IsDataAcquisitionActivated。
private void OnStartMeasurementExecute()
{
IsDataAcquisitionActivated= false;
//... your other code.
}
private void OnStopMeasurementExecute()
{
IsDataAcquisitionActivated= true;
//... your other code.
}
該屬性從視圖模型中設定一次,并且ToggleButton唯一的更新基于它從視圖模型中獲得的屬性更改通知。
另一個想法ToggleButton:如果你真的需要一個ToggleButton. 文本說明了一個動作 Start或Stop,而不是一個狀態(盡管有一個隱含的狀態)。因此,使用單個命令,您可以只使用簡單的Button,無需系結任何狀態。
2. 財產變動法
您可以對屬性更改做出反應。洗掉命令并保留雙向系結。
<ToggleButton x:Name="ButtonMeasurementConnect"
Grid.Row="5" Grid.Column="3"
VerticalAlignment="Center"
Content="{Binding ButtonDataAcquisitionName}"
IsChecked="{Binding IsDataAcquisitionActivated, Mode=TwoWay}">
</ToggleButton>
現在,何時開始或停止測量的唯一指示是屬性的更改,IsDataAcquisitionActivated或者換句話說,何時使用更改的值呼叫其設定器。
public bool IsDataAcquisitionActivated
{
get => _isDataAcquisitionActivated;
set
{
if (_isDataAcquisitionActivated == value)
return;
_isDataAcquisitionActivated= value;
OnPropertyChanged();
if (_isDataAcquisitionActivated)
OnStartMeasurementExecute();
else
OnStopMeasurementExecute();
}
}
那么當然,您的計時器將不再呼叫OnStopMeasurementExecute,而只是設定屬性,因為該方法將被自動呼叫。
if (ts.Seconds >= MeasureTime) IsDataAcquisitionActivated = false;
uj5u.com熱心網友回復:
INotifyPropertyChanged錯誤在于未在系結到IsChecked切換按鈕屬性的屬性中呼叫要實作的函式。
現在它在后面的代碼中設定了計時器,就像按下停止按鈕一樣正確地重置按鈕。
一個缺點是這樣的。由于某種原因,呼叫的方法StopMeasurementCommand連續兩次被觸發,但這是一個不同的問題。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/506327.html
上一篇:在Xamarin表單中將x:DataType設定為ViewModel時,CollectionView專案不會更新
下一篇:為什么我不能系結字串?
