簡體   English   中英

如何從WPF Extended Toolkit正確實現Busy Indicator

[英]How to properly implement Busy Indicator from WPF Extended Toolkit

好吧,我一直在努力解決這個問題很長一段時間,並且已經閱讀了一篇文章,試圖了解這個問題。 我正在嘗試實施忙碌指標,但我只是部分成功。 我有一個Shell視圖,我用BusyIndi​​cator包裝,如下所示:

<Window x:Class="Foundation.Shell"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:controls="clr-namespace:Library.Controls.Views;assembly=Library"
    xmlns:l="clr-namespace:Library.StaticClasses"
    xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
    Name="ShellView"
    Style="{StaticResource BusyWindowStyle}"
    SourceInitialized="Window_SourceInitialized"
    DataContext="{StaticResource ShellVM}">

    <xctk:BusyIndicator x:Name="ShellBusyIndicator" IsBusy="{Binding IsBusy}"  DisplayAfter="0">
        <Grid>
            <!--Content Here -->
        </Grid>
    </xctk:BusyIndicator>

遵循MVVM模式,我有一個看起來像這樣的ShellViewModel:

public class ShellViewModel : ViewModelBase
{
    #region constructor(s)

    public ShellViewModel()
    {
        StateManager.IsBusyChange += new StateManager.IsBusyHandler(IsBusyEventAction);
    }

    #endregion constructor(s)

    #region properties

    private bool _IsBusy;
    public bool IsBusy
    {
        get
        {
            return _IsBusy;
        }
        set
        {
            if (_IsBusy != value)
            {
                _IsBusy = value;
                OnPropertyChanged("IsBusy");
            }
        }
    }

    private string _IsBusyMessage;
    public string IsBusyMessage
    {
        get
        {
            return _IsBusyMessage;
        }
        set
        {
            if (_IsBusyMessage != value)
            {
                _IsBusyMessage = value;
                OnPropertyChanged("IsBusyMessage");
            }
        }
    }

    #endregion properties

    #region actions, functions, and methods

    private void IsBusyEventAction(object sender, EventArgs e)
    {
        if (StateManager.IsBusy)
        {
            this.IsBusy = true;
            this.IsBusyMessage = StateManager.IsBusyMessage;
        }
        else
        {
            this.IsBusy = false;
        }
    }

    #endregion actions, functions, and methods
}

接下來,我使用一個名為StateManager的靜態類,我可以從任何可以觸發忙指示符的地方調用它:

public static class StateManager
{
    public static String IsBusyMessage { get; set; }

    public static void IsBusyProcess(Action action)
    {
        IsBusyProcess(action, "Processing...");
    }

    public static void IsBusyProcess(Action action, String isBusyMessage)
    {
        IsBusyMessage = isBusyMessage;
        IsBusy = true;
        Application.Current.Dispatcher.Invoke(action, System.Windows.Threading.DispatcherPriority.Background);
        IsBusy = false;
    }

    private static bool _IsBusy;
    public static bool IsBusy
    {
        get
        {
            return _IsBusy;
        }
        set
        {
            if (_IsBusy != value)
            {
                _IsBusy = value;

                IsBusyChange(null, null);
            }
        }
    }

    public delegate void IsBusyHandler(object sender, EventArgs e);

    public static event IsBusyHandler IsBusyChange;
}

最后,我在代碼中觸發忙指示符,如下所示:

StateManager.IsBusyProcess(() =>
        {
            this.Validate();

            if (!HasValidationErrors)
            {
                if (this.CustomerControlVM.SaveCustomer() != 0)
                {
                    VehicleControlVM.VehicleModel.CustomerID = this.CustomerControlVM.CustomerModel.CustomerID;
                    this.VehicleControlVM.SaveVehicle();

                    ComplaintsView complaintsControl = new ComplaintsView();

                    (complaintsControl.DataContext as ComplaintsViewModel).CurrentVehicle = this.VehicleControlVM.VehicleModel;
                    (complaintsControl.DataContext as ComplaintsViewModel).CurrentCustomer = this.CustomerControlVM.CustomerModel;
                    StateManager.LoadView(complaintsControl, PageTransitionType.SlideLeft);
                }
            }

            StateManager.IsBusy = false;
        });

總而言之,可以從應用程序的任何位置調用StateManager。 更改StateManager.IsBusy屬性后,將觸發在ShellViewModel中訂閱的事件。 發生這種情況時,ShellViewModel中的IsBusy屬性設置為true,從而導致顯示IsBusy指示符。 邏輯正常工作正在設置ShellViewModel中的IsBusy並且忙指示器按預期顯示。 什么是不正常的是繁忙的指標不動畫。 它只是停滯不前。 我覺得這是一個線程問題但是我對UI線程的理解是傾斜的,或者我沒有看到一些對你來說很明顯的東西。 我意識到IsBusy邏輯不能與UI在同一個線程上,但我認為,由於我的邏輯發生在視圖模型中,它應該不是問題。 我錯了嗎? 任何想法或想法? 另一件可能有用的事情是:我甚至無法顯示指標並創建此帖子已解決: 如何在應用程序shell中實現繁忙指標

好吧,我終於實現了忙碌指標。 這是一項艱巨的任務,但我已經學到了一些東西。 至少我有一些東西可以展示它。 雖然我沒有弄清楚為什么我的代碼沒有按照我發布的那樣工作,但我確實發現我試圖在動作中執行與UI相關的代碼,這肯定會成為一個問題。 我不是百分百肯定,因為我做了一些重寫,而且我沒有足夠的時間來恢復我的代碼來玩它。 但是,問題得到了解答,以下是我實施繁忙指標的方法:

首先,除了可以刪除IsBusy的屬性集和綁定之外,我的視圖中沒有任何更改。 我最終將視頻模型中的事件訂閱移動到視圖后面的代碼中。 我的觀點背后的代碼如下所示:

public partial class Shell : Window
{
    #region Constructor(s)

    public Shell()
    {
        InitializeComponent();
        StateManager.IsBusyChange += new StateManager.IsBusyHandler(InitiateIsBusy);
    }

    #endregion Constructor(s)

    #region Event Actions

    public void InitiateIsBusy(object sender, BusyActionEventArgs e)
    {
        BackgroundWorker worker = new BackgroundWorker();

        worker.DoWork += (o, ea) =>
        {
            e.IsBusyAction.Invoke();
            //Dispatcher.Invoke((Action)(() => e.IsBusyAction()));
        };
        worker.RunWorkerCompleted += (o, ea) =>
        {
            this.ShellBusyIndicator.IsBusy = false;
        };

        this.ShellBusyIndicator.BusyContent = e.BusyMessage;
        this.ShellBusyIndicator.IsBusy = true;

        worker.RunWorkerAsync();
    }

    #endregion Event Actions
}

首先,請注意我創建了擴展EventArgs的BusyActionEventArgs類。 它被放入我的Library項目中,該項目依賴於我的解決方案中的每個項目:

public class BusyActionEventArgs : EventArgs
{
    public Action IsBusyAction { get; set; }
    public string BusyMessage { get; set; }
}

最后,我的StateManager現在看起來像這樣:

public static class StateManager
{
    public static void IsBusyProcess(Action action)
    {
        IsBusyProcess(action, "Processing...");
    }

    public static void IsBusyProcess(Action action, String isBusyMessage)
    {
        BusyActionEventArgs args = new BusyActionEventArgs()
        {
            IsBusyAction = action,
            BusyMessage = isBusyMessage
        };

        IsBusyChange(null, args);
    }

    public delegate void IsBusyHandler(object sender, BusyActionEventArgs e);

    public static event IsBusyHandler IsBusyChange;
}

請注意,我為IsBusyProcess方法創建了一個重載,因此如果我願意,我可以發送自定義忙消息。

現在,如果我從我的問題的代碼片段中修改我實際使用Busy Indicator的代碼,它看起來像這樣:

StateManager.IsBusyProcess(() =>
        {
            this.Validate();

            if (!HasValidationErrors)
            {
                if (this.CustomerControlVM.SaveCustomer() != 0)
                {
                    VehicleControlVM.VehicleModel.CustomerID = this.CustomerControlVM.CustomerModel.CustomerID;
                    this.VehicleControlVM.SaveVehicle();
                }
            }
        });

        ComplaintsView complaintsControl = new ComplaintsView();

        (complaintsControl.DataContext as ComplaintsViewModel).CurrentVehicle = this.VehicleControlVM.VehicleModel;
        (complaintsControl.DataContext as ComplaintsViewModel).CurrentCustomer = this.CustomerControlVM.CustomerModel;
        StateManager.LoadView(complaintsControl, PageTransitionType.SlideLeft);

請注意我從操作范圍中刪除的代碼。 此代碼是UI代碼,如果它在范圍內,將導致錯誤。

我希望這可以幫助那些可能想要實現類似或遇到麻煩的人。 感謝stackoverflow剛剛存在於此。 有時說出(或打字)會有所不同。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM