如何真正避免在Xamarin.Forms中同时单击多个按钮? [英] How to truly avoid multiple buttons being clicked at the same time in Xamarin.Forms?

查看:136
本文介绍了如何真正避免在Xamarin.Forms中同时单击多个按钮?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在视图中使用多个按钮,每个按钮都指向其自己的弹出页面.同时单击多个按钮时,它会一次转到不同的弹出页面.

我创建了一个带有3个按钮的示例内容页面(每个按钮都转到另一个弹出页面)以演示此问题:

XAML页面:

<ContentPage.Content>
    <AbsoluteLayout>

        <!-- button 1 -->
        <Button x:Name="button1" Text="Button 1"
            BackgroundColor="White" Clicked="Button1Clicked"
            AbsoluteLayout.LayoutFlags="All"
            AbsoluteLayout.LayoutBounds="0.5, 0.3, 0.5, 0.1"/>

        <!-- button 2 -->
        <Button x:Name="button2" Text="Button 2"
            BackgroundColor="White" Clicked="Button2Clicked"
            AbsoluteLayout.LayoutFlags="All"
            AbsoluteLayout.LayoutBounds="0.5, 0.5, 0.5, 0.1"/>

        <!-- button 3 -->
        <Button x:Name="button3" Text="Button 3"
            BackgroundColor="White" Clicked="Button3Clicked"
            AbsoluteLayout.LayoutFlags="All"
            AbsoluteLayout.LayoutBounds="0.5, 0.7, 0.5, 0.1"/>

        <!-- popup page 1 -->
        <AbsoluteLayout x:Name="page1" BackgroundColor="#7f000000" IsVisible="false"
            AbsoluteLayout.LayoutFlags="All"
            AbsoluteLayout.LayoutBounds="0.5, 0.5, 1.0, 1.0">
            <BoxView Color="Red"
                AbsoluteLayout.LayoutFlags="All"
                AbsoluteLayout.LayoutBounds="0.5, 0.5, 0.75, 0.3"/>
            <Label Text="Button 1 clicked" TextColor="White"
                HorizontalTextAlignment="Center"
                AbsoluteLayout.LayoutFlags="All"
                AbsoluteLayout.LayoutBounds="0.5, 0.45, 0.75, 0.05"/>
            <Button Text="Back" BackgroundColor="White" Clicked="Back1Clicked"
                AbsoluteLayout.LayoutFlags="All"
                AbsoluteLayout.LayoutBounds="0.5, 0.6, 0.5, 0.1"/>
        </AbsoluteLayout>

        <!-- popup page 2 -->
        <AbsoluteLayout x:Name="page2" BackgroundColor="#7f000000" IsVisible="false"
            AbsoluteLayout.LayoutFlags="All"
            AbsoluteLayout.LayoutBounds="0.5, 0.5, 1.0, 1.0">
            <BoxView Color="Green"
                AbsoluteLayout.LayoutFlags="All"
                AbsoluteLayout.LayoutBounds="0.5, 0.5, 0.75, 0.3"/>
            <Label Text="Button 2 clicked" TextColor="White"
                HorizontalTextAlignment="Center"
                AbsoluteLayout.LayoutFlags="All"
                AbsoluteLayout.LayoutBounds="0.5, 0.45, 0.75, 0.05"/>
            <Button Text="Back" BackgroundColor="White" Clicked="Back2Clicked"
                AbsoluteLayout.LayoutFlags="All"
                AbsoluteLayout.LayoutBounds="0.5, 0.6, 0.5, 0.1"/>
        </AbsoluteLayout>

        <!-- popup page 3 -->
        <AbsoluteLayout x:Name="page3" BackgroundColor="#7f000000" IsVisible="false"
            AbsoluteLayout.LayoutFlags="All"
            AbsoluteLayout.LayoutBounds="0.5, 0.5, 1.0, 1.0">
            <BoxView Color="Blue"
                AbsoluteLayout.LayoutFlags="All"
                AbsoluteLayout.LayoutBounds="0.5, 0.5, 0.75, 0.3"/>
            <Label Text="Button 3 clicked" TextColor="White"
                HorizontalTextAlignment="Center"
                AbsoluteLayout.LayoutFlags="All"
                AbsoluteLayout.LayoutBounds="0.5, 0.45, 0.75, 0.05"/>
            <Button Text="Back" BackgroundColor="White" Clicked="Back3Clicked"
                AbsoluteLayout.LayoutFlags="All"
                AbsoluteLayout.LayoutBounds="0.5, 0.6, 0.5, 0.1"/>
        </AbsoluteLayout>

    </AbsoluteLayout>
</ContentPage.Content>

C#事件处理程序:

void Button1Clicked(object sender, EventArgs e)
{
    // ... do something first ...
    page1.IsVisible = true;
    Console.WriteLine("Button 1 Clicked!");
}

void Button2Clicked(object sender, EventArgs e)
{
    // ... do something first ...
    page2.IsVisible = true;
    Console.WriteLine("Button 2 Clicked!");
}

void Button3Clicked(object sender, EventArgs e)
{
    // ... do something first ...
    page3.IsVisible = true;
    Console.WriteLine("Button 3 Clicked!");
}

void Back1Clicked(object sender, EventArgs e)
{
    page1.IsVisible = false;
}

void Back2Clicked(object sender, EventArgs e)
{
    page2.IsVisible = false;
}

void Back3Clicked(object sender, EventArgs e)
{
    page3.IsVisible = false;
}

预期:
单击button1将打开page1弹出页面,然后单击弹出窗口中的后退"按钮将隐藏弹出页面. button2button3的行为类似.

实际:
同时单击多个按钮(例如button1button2)将打开两个弹出页面(page1page2).快速双击单个按钮也可以触发同一按钮两次.


关于避免双击的一些研究
通过在stackoverflow中搜索类似的问题(例如 this this ),我来到结论中应该设置一个外部变量来控制是否执行事件.这是我在Xamarin.forms中的实现:

将C#结构作为外部变量,以便我可以在单独的类中访问此变量:

// struct to avoid multiple button click at the same time
public struct S
{
    // control whether the button events are executed
    public static bool AllowTap = true;

    // wait for 200ms after allowing another button event to be executed
    public static async void ResumeTap() {
        await Task.Delay(200);
        AllowTap = true;
    }
}

然后对每个按钮事件处理程序进行如下修改(对Button2Clicked()Button3Clicked()同样适用):

void Button1Clicked(object sender, EventArgs e)
{
    // if some buttons are clicked recently, stop executing the method
    if (!S.AllowTap) return; S.AllowTap = false; //##### * NEW * #####//

    // ... do something first ...
    page1.IsVisible = true;
    Console.WriteLine("Button 1 Clicked!");

    // allow other button's event to be fired after the wait specified in struct S
    S.ResumeTap(); //##### * NEW * #####//
}

这通常效果很好.双击同一按钮可以快速触发一次按钮事件,并且同时单击多个按钮只会打开1个弹出页面.


真正的问题
如上所述,在修改代码(在struct S中添加共享状态变量AllowTap)之后,仍然有可能打开多个弹出页面.例如,如果用户用两根手指按住button1button2,释放button1,等待大约一秒钟,然后释放button2,将同时打开弹出页面page1page2.


解决此问题的尝试失败
如果尝试单击button1button2button3,我尝试禁用所有按钮,如果单击后退按钮,则尝试启用所有按钮.

void disableAllButtons()
{
    button1.IsEnabled = false;
    button2.IsEnabled = false;
    button3.IsEnabled = false;
}

void enableAllButtons()
{
    button1.IsEnabled = true;
    button2.IsEnabled = true;
    button3.IsEnabled = true;
}

然后对每个按钮事件处理程序进行如下修改(对Button2Clicked()Button3Clicked()同样适用):

void Button1Clicked(object sender, EventArgs e)
{
    if (!S.AllowTap) return; S.AllowTap = false;

    // ... do something first ...
    disableAllButtons(); //##### * NEW * #####//
    page1.IsVisible = true;
    Console.WriteLine("Button 1 Clicked!");

    S.ResumeTap();
}

每个后退按钮事件处理程序都进行了这样的修改(对Back2Clicked()Back3Clicked()同样适用):

void Back1Clicked(object sender, EventArgs e)
{
    page1.IsVisible = false;
    enableAllButtons(); //##### * NEW * #####//
}

但是,相同的问题仍然存在(可以按住另一个按钮,稍后再释放它们以同时触发2个按钮).


在我的应用程序中禁用多点触控是不可行的,因为我需要在我的应用程序的其他页面中使用它.另外,弹出页面可能还包含多个指向其他页面的按钮,因此,仅使用弹出页面中的后退按钮在struct S中设置变量AllowTap也是一种选择.

任何帮助将不胜感激.谢谢.

编辑
"真正的问题"会影响Android和iOS.在Android设备上,用户按住按钮一段时间后,一旦禁用该按钮,就无法激活该按钮.这个禁用按钮的问题不会影响iOS中的按钮.

解决方案

我建议使用MVVM方法,并将每个按钮的IsEnabled属性绑定到视图模型中的相同属性,例如:

MyViewModel.cs :

private bool _areButtonsEnabled = true;

public bool AreButtonsEnabled
{
    get => _areButtonsEnabled;
    set
    {
        if (_areButtonsEnabled != value)
        {
            _areButtonsEnabled = value;
            OnPropertyChanged(nameof(AreButtonsEnabled)); // assuming your view model implements INotifyPropertyChanged
        }
    }
}

MyPage.xaml (仅显示一个按钮的代码):

...
<Button 
    Text="Back" 
    BackgroundColor="White" 
    Clicked="HandleButton1Clicked"
    AbsoluteLayout.LayoutFlags="All"
    AbsoluteLayout.LayoutBounds="0.5, 0.6, 0.5, 0.1"
    IsEnabled={Binding AreButtonsEnabled} />
...

然后为每个按钮的事件处理程序,可以将AreButtonsEnabled属性设置为false以禁用所有按钮.请注意,您应该首先检查AreButtonsEnabled的值是否为true,因为在调用PropertyChanged事件之前,用户有可能单击两次.但是,由于按钮的click事件处理程序在主线程上运行,因此在调用下一个HandleButtonXClicked之前,AreButtonsEnabled的值将设置为false.换句话说,即使UI尚未更新,AreButtonsEnabled的值也将被更新.

MyPage.xaml.cs :

HandleButton1Clicked(object sender, EventArgs e)
{
    if (viewModel.AreButtonsEnabled)
    {
        viewModel.AreButtonsEnabled = false;
        // button 1 code...
    }
}

HandleButton2Clicked(object sender, EventArgs e)
{
    if (viewModel.AreButtonsEnabled)
    {
        viewModel.AreButtonsEnabled = false;
        // button 2 code...
    }
}

HandleButton3Clicked(object sender, EventArgs e)
{
    if (viewModel.AreButtonsEnabled)
    {
        viewModel.AreButtonsEnabled = false;
        // button 3 code...
    }
}

然后当您想重新启用按钮时只调用viewModel.AreButtonsEnabled = true;.


如果您想要真实的" MVVM模式,可以将Commands绑定到按钮上,而不是监听它们的Clicked事件.

MyViewModel.cs :

private bool _areButtonsEnabled = true;

public bool AreButtonsEnabled
{
    get => _areButtonsEnabled;
    set
    {
        if (_areButtonsEnabled != value)
        {
            _areButtonsEnabled = value;
            OnPropertyChanged(nameof(AreButtonsEnabled)); // assuming your view model implements INotifyPropertyChanged
        }
    }
}

public ICommand Button1Command { get; protected set; }

public MyViewModel()
{
    Button1Command = new Command(HandleButton1Tapped);
}

private void HandleButton1Tapped()
{
    // Run on the main thread, to make sure that it is getting/setting the proper value for AreButtonsEnabled
    // And note that calls to Device.BeginInvokeOnMainThread are queued, therefore
    // you can be assured that AreButtonsEnabled will be set to false by one button's command
    // before the value of AreButtonsEnabled is checked by another button's command.
    // (Assuming you don't change the value of AreButtonsEnabled on another thread)
    Device.BeginInvokeOnMainThread(() => 
    {
        if (AreButtonsEnabled)
        {
            AreButtonsEnabled = false;
            // button 1 code...
        }
    });
}

// don't forget to add Commands for Button 2 and 3

MyPage.xaml (仅显示一个按钮):

<Button 
    Text="Back" 
    BackgroundColor="White"
    AbsoluteLayout.LayoutFlags="All"
    AbsoluteLayout.LayoutBounds="0.5, 0.6, 0.5, 0.1"
    Command={Binding Button1Command}
    IsEnabled={Binding AreButtonsEnabled} />

现在您无需在MyPage.xaml.cs代码隐藏文件中添加任何代码.

I am using multiple buttons in a view, and each button leads to its own popup page. While clicking multiple button simultaneously, it goes to different popup pages at a time.

I created a sample content page with 3 buttons (each goes to a different popup page) to demonstrate this issue:

XAML page:

<ContentPage.Content>
    <AbsoluteLayout>

        <!-- button 1 -->
        <Button x:Name="button1" Text="Button 1"
            BackgroundColor="White" Clicked="Button1Clicked"
            AbsoluteLayout.LayoutFlags="All"
            AbsoluteLayout.LayoutBounds="0.5, 0.3, 0.5, 0.1"/>

        <!-- button 2 -->
        <Button x:Name="button2" Text="Button 2"
            BackgroundColor="White" Clicked="Button2Clicked"
            AbsoluteLayout.LayoutFlags="All"
            AbsoluteLayout.LayoutBounds="0.5, 0.5, 0.5, 0.1"/>

        <!-- button 3 -->
        <Button x:Name="button3" Text="Button 3"
            BackgroundColor="White" Clicked="Button3Clicked"
            AbsoluteLayout.LayoutFlags="All"
            AbsoluteLayout.LayoutBounds="0.5, 0.7, 0.5, 0.1"/>

        <!-- popup page 1 -->
        <AbsoluteLayout x:Name="page1" BackgroundColor="#7f000000" IsVisible="false"
            AbsoluteLayout.LayoutFlags="All"
            AbsoluteLayout.LayoutBounds="0.5, 0.5, 1.0, 1.0">
            <BoxView Color="Red"
                AbsoluteLayout.LayoutFlags="All"
                AbsoluteLayout.LayoutBounds="0.5, 0.5, 0.75, 0.3"/>
            <Label Text="Button 1 clicked" TextColor="White"
                HorizontalTextAlignment="Center"
                AbsoluteLayout.LayoutFlags="All"
                AbsoluteLayout.LayoutBounds="0.5, 0.45, 0.75, 0.05"/>
            <Button Text="Back" BackgroundColor="White" Clicked="Back1Clicked"
                AbsoluteLayout.LayoutFlags="All"
                AbsoluteLayout.LayoutBounds="0.5, 0.6, 0.5, 0.1"/>
        </AbsoluteLayout>

        <!-- popup page 2 -->
        <AbsoluteLayout x:Name="page2" BackgroundColor="#7f000000" IsVisible="false"
            AbsoluteLayout.LayoutFlags="All"
            AbsoluteLayout.LayoutBounds="0.5, 0.5, 1.0, 1.0">
            <BoxView Color="Green"
                AbsoluteLayout.LayoutFlags="All"
                AbsoluteLayout.LayoutBounds="0.5, 0.5, 0.75, 0.3"/>
            <Label Text="Button 2 clicked" TextColor="White"
                HorizontalTextAlignment="Center"
                AbsoluteLayout.LayoutFlags="All"
                AbsoluteLayout.LayoutBounds="0.5, 0.45, 0.75, 0.05"/>
            <Button Text="Back" BackgroundColor="White" Clicked="Back2Clicked"
                AbsoluteLayout.LayoutFlags="All"
                AbsoluteLayout.LayoutBounds="0.5, 0.6, 0.5, 0.1"/>
        </AbsoluteLayout>

        <!-- popup page 3 -->
        <AbsoluteLayout x:Name="page3" BackgroundColor="#7f000000" IsVisible="false"
            AbsoluteLayout.LayoutFlags="All"
            AbsoluteLayout.LayoutBounds="0.5, 0.5, 1.0, 1.0">
            <BoxView Color="Blue"
                AbsoluteLayout.LayoutFlags="All"
                AbsoluteLayout.LayoutBounds="0.5, 0.5, 0.75, 0.3"/>
            <Label Text="Button 3 clicked" TextColor="White"
                HorizontalTextAlignment="Center"
                AbsoluteLayout.LayoutFlags="All"
                AbsoluteLayout.LayoutBounds="0.5, 0.45, 0.75, 0.05"/>
            <Button Text="Back" BackgroundColor="White" Clicked="Back3Clicked"
                AbsoluteLayout.LayoutFlags="All"
                AbsoluteLayout.LayoutBounds="0.5, 0.6, 0.5, 0.1"/>
        </AbsoluteLayout>

    </AbsoluteLayout>
</ContentPage.Content>

C# event handlers:

void Button1Clicked(object sender, EventArgs e)
{
    // ... do something first ...
    page1.IsVisible = true;
    Console.WriteLine("Button 1 Clicked!");
}

void Button2Clicked(object sender, EventArgs e)
{
    // ... do something first ...
    page2.IsVisible = true;
    Console.WriteLine("Button 2 Clicked!");
}

void Button3Clicked(object sender, EventArgs e)
{
    // ... do something first ...
    page3.IsVisible = true;
    Console.WriteLine("Button 3 Clicked!");
}

void Back1Clicked(object sender, EventArgs e)
{
    page1.IsVisible = false;
}

void Back2Clicked(object sender, EventArgs e)
{
    page2.IsVisible = false;
}

void Back3Clicked(object sender, EventArgs e)
{
    page3.IsVisible = false;
}

Expected:
Clicking button1 opens page1 popup page, and clicking the back button in the popup hides the popup page. Similar behavious for button2 and button3.

Actual:
Clicking multiple buttons (eg. button1 and button2) at the same time opens both popup pages (page1 and page2). Double clicking a single button quickly can also fire the same button twice.


Some research on avoid double clicking
By searching similar questions in stackoverflow (such as this and this), I come to a conclusion where you should set an external variable to control whether the events are executed or not. This is my implementation in Xamarin.forms:

C# struct as the external variable so that I can access this variable in separate classes:

// struct to avoid multiple button click at the same time
public struct S
{
    // control whether the button events are executed
    public static bool AllowTap = true;

    // wait for 200ms after allowing another button event to be executed
    public static async void ResumeTap() {
        await Task.Delay(200);
        AllowTap = true;
    }
}

Then each button event handler is modified like this (same applies to Button2Clicked() and Button3Clicked()):

void Button1Clicked(object sender, EventArgs e)
{
    // if some buttons are clicked recently, stop executing the method
    if (!S.AllowTap) return; S.AllowTap = false; //##### * NEW * #####//

    // ... do something first ...
    page1.IsVisible = true;
    Console.WriteLine("Button 1 Clicked!");

    // allow other button's event to be fired after the wait specified in struct S
    S.ResumeTap(); //##### * NEW * #####//
}

This works generally pretty well. Double-tapping the same button quickly fire the button event once only, and clicking multiple buttons at the same time only open 1 popup page.


The Real Problem
It's still possible to open more than 1 popup pages after modifing the code (adding a shared state variable AllowTap in struct S) as described above. E.g., if the user hold down button1 and button2 using 2 fingers, release button1, wait for around a second, and then release button2, both popup pages page1 and page2 will be opened.


A failed attempt to fix this issue
I tried to disable all buttons if either button1, button2 or button3 is clicked, and enable all buttons if the back button is clicked.

void disableAllButtons()
{
    button1.IsEnabled = false;
    button2.IsEnabled = false;
    button3.IsEnabled = false;
}

void enableAllButtons()
{
    button1.IsEnabled = true;
    button2.IsEnabled = true;
    button3.IsEnabled = true;
}

Then each button event handler is modified like this (same applies to Button2Clicked() and Button3Clicked()):

void Button1Clicked(object sender, EventArgs e)
{
    if (!S.AllowTap) return; S.AllowTap = false;

    // ... do something first ...
    disableAllButtons(); //##### * NEW * #####//
    page1.IsVisible = true;
    Console.WriteLine("Button 1 Clicked!");

    S.ResumeTap();
}

And each back button event handler is modified like this (same applies to Back2Clicked() and Back3Clicked()):

void Back1Clicked(object sender, EventArgs e)
{
    page1.IsVisible = false;
    enableAllButtons(); //##### * NEW * #####//
}

However, the same issue still persists (able to hold another button and release them later to fire 2 buttons simultaneously).


Disabling multi-touch in my app won't be an option, since I need that in other pages in my app. Also, the popup pages may also contain multiple buttons which leads to other pages as well, so simply using the back button in the popup page to set the variable AllowTap in struct S won't be an option as well.

Any help will be appreciated. Thanks.

EDIT
"The Real Problem" affects both Android and iOS. On Android, a button can't be activated once the button is disabled some time when the user is holding the button. This holding-a-disabled-button issue does not affect buttons in iOS.

解决方案

I'd recommend using a MVVM approach, and binding the IsEnabled property for each button to the same property in the View Model, for example, AreButtonsEnabled:

MyViewModel.cs:

private bool _areButtonsEnabled = true;

public bool AreButtonsEnabled
{
    get => _areButtonsEnabled;
    set
    {
        if (_areButtonsEnabled != value)
        {
            _areButtonsEnabled = value;
            OnPropertyChanged(nameof(AreButtonsEnabled)); // assuming your view model implements INotifyPropertyChanged
        }
    }
}

MyPage.xaml (code for just one button shown):

...
<Button 
    Text="Back" 
    BackgroundColor="White" 
    Clicked="HandleButton1Clicked"
    AbsoluteLayout.LayoutFlags="All"
    AbsoluteLayout.LayoutBounds="0.5, 0.6, 0.5, 0.1"
    IsEnabled={Binding AreButtonsEnabled} />
...

Then for the event handlers for each button, you can set the AreButtonsEnabled property to false to disable all buttons. Note that you should first check if the value of AreButtonsEnabled is true, because there is a chance the user can click twice before the PropertyChanged event is invoked. However, because the buttons' click event handlers run on the main thread, the value of AreButtonsEnabled will be set to false before the next HandleButtonXClicked is called. In other words, the value of AreButtonsEnabled will be updated, even if the UI has not updated yet.

MyPage.xaml.cs:

HandleButton1Clicked(object sender, EventArgs e)
{
    if (viewModel.AreButtonsEnabled)
    {
        viewModel.AreButtonsEnabled = false;
        // button 1 code...
    }
}

HandleButton2Clicked(object sender, EventArgs e)
{
    if (viewModel.AreButtonsEnabled)
    {
        viewModel.AreButtonsEnabled = false;
        // button 2 code...
    }
}

HandleButton3Clicked(object sender, EventArgs e)
{
    if (viewModel.AreButtonsEnabled)
    {
        viewModel.AreButtonsEnabled = false;
        // button 3 code...
    }
}

And then just called viewModel.AreButtonsEnabled = true; when you want to re-enable the buttons.


If you want a "true" MVVM pattern, you can bind Commands to the buttons instead of listening to their Clicked events.

MyViewModel.cs:

private bool _areButtonsEnabled = true;

public bool AreButtonsEnabled
{
    get => _areButtonsEnabled;
    set
    {
        if (_areButtonsEnabled != value)
        {
            _areButtonsEnabled = value;
            OnPropertyChanged(nameof(AreButtonsEnabled)); // assuming your view model implements INotifyPropertyChanged
        }
    }
}

public ICommand Button1Command { get; protected set; }

public MyViewModel()
{
    Button1Command = new Command(HandleButton1Tapped);
}

private void HandleButton1Tapped()
{
    // Run on the main thread, to make sure that it is getting/setting the proper value for AreButtonsEnabled
    // And note that calls to Device.BeginInvokeOnMainThread are queued, therefore
    // you can be assured that AreButtonsEnabled will be set to false by one button's command
    // before the value of AreButtonsEnabled is checked by another button's command.
    // (Assuming you don't change the value of AreButtonsEnabled on another thread)
    Device.BeginInvokeOnMainThread(() => 
    {
        if (AreButtonsEnabled)
        {
            AreButtonsEnabled = false;
            // button 1 code...
        }
    });
}

// don't forget to add Commands for Button 2 and 3

MyPage.xaml (Only one button shown):

<Button 
    Text="Back" 
    BackgroundColor="White"
    AbsoluteLayout.LayoutFlags="All"
    AbsoluteLayout.LayoutBounds="0.5, 0.6, 0.5, 0.1"
    Command={Binding Button1Command}
    IsEnabled={Binding AreButtonsEnabled} />

And now you don't need to add any code in your MyPage.xaml.cs code-behind file.

这篇关于如何真正避免在Xamarin.Forms中同时单击多个按钮?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆