第二十章:非同步和檔案I/O.(二十一)
因此,MandelbrotViewModel類具有許多屬性,但如果您不考慮使用者介面,則可能與您定義的屬性不同。 CurrentCenter屬性是程式當前顯示的影像中心的複數,CurrentMagnification也適用於該影像。 但TargetMagnification繫結到Stepper的當前設定,它將應用於下一個計算的影像。 RealOffset和ImaginaryOffset屬性繫結到兩個Slider元素,範圍從0到1.從CurrentCenter,CurrentMagnification,RealOffset和ImaginaryOffset屬性,ViewModel可以計算TargetCenter屬性。 這是下一個計算影像的中心。 如您所見,該TargetCenter屬性用於顯示兩個滑塊下方的複數:
namespace MandelbrotXF
{
class MandelbrotViewModel : ViewModelBase
{
// Set via constructor arguments.
readonly double baseWidth;
readonly double baseHeight;
// Backing fields for properties.
Complex currentCenter, targetCenter;
int pixelWidth, pixelHeight;
double currentMagnification, targetMagnification;
int iterations;
double realOffset, imaginaryOffset;
bool isBusy;
double progress;
BitmapInfo bitmapInfo;
public MandelbrotViewModel(double baseWidth, double baseHeight)
{
this.baseWidth = baseWidth;
this.baseHeight = baseHeight;
// Create MandelbrotModel object.
MandelbrotModel model = new MandelbrotModel();
// Progress reporter
Progress<double> progressReporter = new Progress<double>((double progress) =>
{
Progress = progress;
});
CancellationTokenSource cancelTokenSource = null;
// Define CalculateCommand and CancelCommand.
CalculateCommand = new Command(
execute: async () =>
{
// Disable this button and enable Cancel button.
IsBusy = true;
((Command)CalculateCommand).ChangeCanExecute();
((Command)CancelCommand).ChangeCanExecute();
// Create CancellationToken.
cancelTokenSource = new CancellationTokenSource();
CancellationToken cancelToken = cancelTokenSource.Token;
try
{
// Perform the calculation.
BitmapInfo = await model.CalculateAsync(TargetCenter,
baseWidth / TargetMagnification,
baseHeight / TargetMagnification,
PixelWidth, PixelHeight,
Iterations,
progressReporter,
cancelToken);
// Processing only for a successful completion.
CurrentCenter = TargetCenter;
CurrentMagnification = TargetMagnification;
RealOffset = 0.5;
ImaginaryOffset = 0.5;
}
catch (OperationCanceledException)
{
// Operation cancelled!
}
catch
{
// Another type of exception? This should not occur.
}
// Processing regardless of success or cancellation.
Progress = 0;
IsBusy = false;
// Disable Cancel button and enable this button.
((Command)CalculateCommand).ChangeCanExecute();
((Command)CancelCommand).ChangeCanExecute();
},
canExecute: () =>
{
return !IsBusy;
});
CancelCommand = new Command(
execute: () =>
{
cancelTokenSource.Cancel();
},
canExecute: () =>
{
return IsBusy;
});
}
public int PixelWidth
{
set { SetProperty(ref pixelWidth, value); }
get { return pixelWidth; }
}
public int PixelHeight
{
set { SetProperty(ref pixelHeight, value); }
get { return pixelHeight; }
}
public Complex CurrentCenter
{
set
{
if (SetProperty(ref currentCenter, value))
CalculateTargetCenter();
}
get { return currentCenter; }
}
public Complex TargetCenter
{
private set { SetProperty(ref targetCenter, value); }
get { return targetCenter; }
}
public double CurrentMagnification
{
set { SetProperty(ref currentMagnification, value); }
get { return currentMagnification; }
}
public double TargetMagnification
{
set { SetProperty(ref targetMagnification, value); }
get { return targetMagnification; }
}
public int Iterations
{
set { SetProperty(ref iterations, value); }
get { return iterations; }
}
// These two properties range from 0 to 1.
// They indicate a new center relative to the
// current width and height, which is the baseWidth
// and baseHeight divided by CurrentMagnification.
public double RealOffset
{
set
{
if (SetProperty(ref realOffset, value))
CalculateTargetCenter();
}
get { return realOffset; }
}
public double ImaginaryOffset
{
set
{
if (SetProperty(ref imaginaryOffset, value))
CalculateTargetCenter();
}
get { return imaginaryOffset; }
}
void CalculateTargetCenter()
{
double width = baseWidth / CurrentMagnification;
double height = baseHeight / CurrentMagnification;
TargetCenter = new Complex(CurrentCenter.Real + (RealOffset - 0.5) * width,
CurrentCenter.Imaginary + (ImaginaryOffset - 0.5) *
height);
}
public bool IsBusy
{
private set { SetProperty(ref isBusy, value); }
get { return isBusy; }
}
public double Progress
{
private set { SetProperty(ref progress, value); }
get { return progress; }
}
public BitmapInfo BitmapInfo
{
private set { SetProperty(ref bitmapInfo, value); }
get { return bitmapInfo; }
}
public ICommand CalculateCommand { private set; get; }
public ICommand CancelCommand { private set; get; }
}
}
MandelbrotViewModel還為Calculate和Cancel按鈕,Progress屬性和IsBusy屬性定義了ICommand型別的兩個屬性。 正如您將看到的,IsBusy屬性用於顯示這兩個按鈕中的一個並隱藏另一個按鈕,並在計算過程中禁用其餘的使用者介面。 這兩個ICommand屬性是在類的建構函式中使用lambda函式實現的。
XAML檔案中的資料繫結到MandelbrotViewModel中的屬性需要Xamarin.FormsBook.Toolkit庫中的兩個新繫結轉換器。 第一個簡單地否定了bool值:
namespace Xamarin.FormsBook.Toolkit
{
public class BooleanNegationConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
return !(bool)value;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
return !(bool)value;
}
}
}
它與ViewModel的IsBusy屬性一起使用。 當IsBusy為true時,需要將幾個元素的IsEnabled屬性和Go按鈕的IsVisible屬性設定為false。
兩個Stepper元素實際上控制ViewModel中值的指數。 例如,Stepper值為8,對應於Iterations或TargetMagnification值256.該轉換需要base-2對數轉換器:
namespace Xamarin.FormsBook.Toolkit
{
public class BaseTwoLogConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
if (value is int)
{
return Math.Log((int)value) / Math.Log(2);
}
return Math.Log((double)value) / Math.Log(2);
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
double returnValue = Math.Pow(2, (double)value);
if (targetType == typeof(int))
{
return (int) returnValue;
}
return returnValue;
}
}
}
這是XAML檔案,繫結到ViewModel的Progress,RealOffset,ImaginaryOffset,TargetCenter,TargetMagnification,Iterations,IsBusy,CalculateCommand和CancelCommand屬性:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:toolkit=
"clr-namespace:Xamarin.FormsBook.Toolkit;assembly=Xamarin.FormsBook.Toolkit"
x:Class="MandelbrotXF.MandelbrotXFPage"
SizeChanged="OnPageSizeChanged">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness"
iOS="0, 20, 0, 0" />
</ContentPage.Padding>
<ContentPage.Resources>
<ResourceDictionary>
<toolkit:BooleanNegationConverter x:Key="negate" />
<toolkit:BaseTwoLogConverter x:Key="base2log" />
</ResourceDictionary>
</ContentPage.Resources>
<Grid x:Name="mainGrid">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="0" />
</Grid.ColumnDefinitions>
<!-- Image for determining pixels per unit. -->
<Image x:Name="testImage"
Grid.Row="0" Grid.Column="0"
Opacity="0"
HorizontalOptions="Center"
VerticalOptions="Center" />
<!-- Image for Mandelbrot Set. -->
<Image x:Name="image"
Grid.Row="0" Grid.Column="0"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
SizeChanged="OnImageSizeChanged" />
<AbsoluteLayout x:Name="crossHairLayout"
Grid.Row="0" Grid.Column="0"
HorizontalOptions="Center"
VerticalOptions="Center"
SizeChanged="OnCrossHairLayoutSizeChanged">
<AbsoluteLayout.Resources>
<ResourceDictionary>
<Style TargetType="BoxView">
<Setter Property="Color" Value="White" />
<Setter Property="AbsoluteLayout.LayoutBounds" Value="0,0,0,0" />
</Style>
</ResourceDictionary>
</AbsoluteLayout.Resources>
<BoxView x:Name="realCrossHair" />
<BoxView x:Name="imagCrossHair" />
<BoxView x:Name="topBox" />
<BoxView x:Name="bottomBox" />
<BoxView x:Name="leftBox" />
<BoxView x:Name="rightBox" />
</AbsoluteLayout>
<StackLayout x:Name="controlPanelStack"
Grid.Row="1" Grid.Column="0"
Padding="10">
<ProgressBar Progress="{Binding Progress}"
VerticalOptions="CenterAndExpand" />
<StackLayout VerticalOptions="CenterAndExpand">
<Slider Value="{Binding RealOffset, Mode=TwoWay}"
IsEnabled="{Binding IsBusy, Converter={StaticResource negate}}" />
<Slider Value="{Binding ImaginaryOffset, Mode=TwoWay}"
IsEnabled="{Binding IsBusy, Converter={StaticResource negate}}" />
<Label Text="{Binding TargetCenter, StringFormat=`{0}`}"
FontSize="Small"
HorizontalTextAlignment="Center" />
</StackLayout>
<Grid VerticalOptions="CenterAndExpand">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!-- Magnification factor stepper and display. -->
<Stepper x:Name="magnificationStepper"
Grid.Row="0" Grid.Column="0"
Value="{Binding TargetMagnification,
Converter={StaticResource base2log}}"
IsEnabled="{Binding IsBusy, Converter={StaticResource negate}}"
VerticalOptions="Center" />
<StackLayout Grid.Row="0" Grid.Column="1"
Orientation="Horizontal"
Spacing="0"
VerticalOptions="Start">
<Label Text="zoom 2"
FontSize="Medium" />
<Label Text="{Binding Source={x:Reference magnificationStepper},
Path=Value,
StringFormat=`{0}`}"
FontSize="Micro" />
</StackLayout>
<!-- Iterations factor stepper and display. -->
<Stepper x:Name="iterationsStepper"
Grid.Row="1" Grid.Column="0"
Value="{Binding Iterations, Converter={StaticResource base2log}}"
IsEnabled="{Binding IsBusy, Converter={StaticResource negate}}"
VerticalOptions="Center" />
<StackLayout Grid.Row="1" Grid.Column="1"
Orientation="Horizontal"
Spacing="0"
VerticalOptions="End">
<Label Text="loop 2"
FontSize="Medium" />
<Label Text="{Binding Source={x:Reference iterationsStepper},
Path=Value,
StringFormat=`{0}`}"
FontSize="Micro" />
</StackLayout>
<!-- Go / Cancel buttons. -->
<Grid Grid.Row="0" Grid.Column="1" Grid.RowSpan="2"
HorizontalOptions="End"
VerticalOptions="Center">
<Button Text="Go"
Command="{Binding CalculateCommand}"
IsVisible="{Binding IsBusy, Converter={StaticResource negate}}" />
<Button Text="Cancel"
Command="{Binding CancelCommand}"
IsVisible="{Binding IsBusy}" />
</Grid>
</Grid>
</StackLayout>
</Grid>
</ContentPage>
此XAML檔案僅安裝三個事件處理程式,它們都是SizeChanged處理程式。
相關文章
- 第二十章:非同步和檔案I/O.(一)非同步
- 第二十章:非同步和檔案I/O.(九)非同步
- 第二十章:非同步和檔案I/O.(八)非同步
- 第二十章:非同步和檔案I/O.(十四)非同步
- 第二十章:非同步和檔案I/O.(二)非同步
- 第二十章:非同步和檔案I/O.(二十三)非同步
- socket阻塞與非阻塞,同步與非同步、I/O模型非同步模型
- 檔案備份和同步工具:Syncovery for mac v9.49i啟用版Mac
- Linux-檔案寫入和檔案同步Linux
- ♻️同步和非同步;並行和併發;阻塞和非阻塞非同步並行
- 雲備份和同步檔案資料
- rsync同步和備份檔案到本地
- 談談對不同I/O模型的理解 (阻塞/非阻塞IO,同步/非同步IO)模型非同步
- iGuard和NFS檔案同步的解決方案NFS
- 實現手機和PC檔案同步 GitLab和TermuxGitlabUX
- Python:讀寫檔案(I/O) | 組織檔案Python
- 054 非單檔案元件元件
- 第二章 檔案和目錄操作命令
- Java 非阻塞 IO 和非同步 IOJava非同步
- 使用Unison 同步檔案
- Java基礎 第二節 第二十一課Java
- 同步非同步,阻塞非阻塞非同步
- 非同步、同步、阻塞、非阻塞非同步
- 使用ln同步檔案內容,支援忽略檔案
- Mac檔案同步軟體Mac
- Java中I/O流:阻塞和非阻塞範例Java
- 免費檔案同步軟體有哪些?檔案同步軟體哪個好
- 第二十一章:變換(四)
- 前端週刊第二十一期前端
- http不使用Form表單傳送檔案資料和非檔案資料(上傳篇)HTTPORM
- 同步、非同步,阻塞、非阻塞理解非同步
- 同步、非同步、阻塞與非阻塞非同步
- 同步非同步 與 阻塞非阻塞非同步
- 理解阻塞、非阻塞、同步、非同步非同步
- 檔案同步是什麼?解析6個最佳的檔案同步應用軟體
- Linux 檔案同步工具之 rsyncLinux
- ios檔案同步傳輸工具iOS
- 對執行緒、協程和同步非同步、阻塞非阻塞的理解執行緒非同步