簡體   English   中英

從另一個線程更新網格的可見性

[英]Update visibility of grid from another thread

問題:

我有以下課程:

1)SMServiceClient-RestSharp的包裝器

public class SMServiceClient
{
    public delegate void AuthorizationSucceededHandler(SMServiceEventArgs args);
    public event AuthorizationSucceededHandler AuthorizationSucceeded;

    public delegate void AuthorizationFailedHandler(SMServiceEventArgs args);
    public event AuthorizationFailedHandler AuthorizationFailed;

    public delegate void RequestStartedHandler(SMServiceEventArgs args);
    public event RequestStartedHandler RequestStarted;

    public delegate void RequestFinishedHandler(SMServiceEventArgs args);
    public event RequestFinishedHandler RequestFinished;


    private const string baseUrl = "http://10.0.0.6:4000";
    private RestClient client;

    public SMServiceClient()
    {
        client = new RestClient(baseUrl);
        client.CookieContainer = new CookieContainer();
        client.FollowRedirects = false;
    }

    public void AuthUser(string username, string password)
    {
        RequestStarted(new SMServiceEventArgs());
        var request = new RestRequest("/api/login", Method.POST);
        request.AddParameter("username", username);
        request.AddParameter("password", password);
        var response = client.Execute<User>(request);
        if (response.StatusCode == HttpStatusCode.Unauthorized)
        {
            AuthorizationFailed(new SMServiceEventArgs("Credential are incorrect!"));
        }
        else {
            AuthorizationSucceeded(new SMServiceEventArgs(response.Data));
        }
        RequestFinished(new SMServiceEventArgs());
    }
}

2)ViewModel-用於存儲接收到的數據和綁定的類

public class ViewModel : INotifyPropertyChanged
{
    private SMServiceClient _client;
    public SMServiceClient client { get { return _client; } }

    private Credentials _currentLogging;
    public Credentials currentLogging
    {
        get { return _currentLogging; }
        set
        {
            if (_currentLogging != value)
            {
                _currentLogging = value;
                OnPropertyChanged(new PropertyChangedEventArgs("currentLogging"));
            }
        }
    }

    public ViewModel() 
    {
        _client = new SMServiceClient();
        currentLogging = new Credentials();
    }

    public void AuthUser()
    {
        _client.AuthUser(currentLogging.login, currentLogging.password);
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
            handler(this, e);
    }
}

3)MainWindow.xaml.cs-應用程序的主窗口

public partial class MainWindow : MetroWindow
{
    public ViewModel _viewModel;
    public MainWindow()
    {
        InitializeComponent();
        _viewModel = new ViewModel();
        _viewModel.client.AuthorizationSucceeded += ServiceClient_AuthorizationSucceeded;
        _viewModel.client.AuthorizationFailed += ServiceClient_AuthorizationFailed;
        _viewModel.client.RequestStarted += ServiceClient_RequestStarted;
        _viewModel.client.RequestFinished += ServiceClient_RequestFinished;

        this.DataContext = _viewModel;
    }

    void ServiceClient_RequestStarted(SMServiceEventArgs args)
    {
        this.Dispatcher.BeginInvoke(new Action(() => { overlayThrobber.Visibility = System.Windows.Visibility.Visible; }), DispatcherPriority.Normal);
    }

    void ServiceClient_RequestFinished(SMServiceEventArgs args)
    {
        this.Dispatcher.BeginInvoke(new Action(() => { overlayThrobber.Visibility = System.Windows.Visibility.Collapsed; }), DispatcherPriority.Normal);
    }

    void ServiceClient_AuthorizationSucceeded(SMServiceEventArgs args)
    {
        _viewModel.loggedUser = args.loggedUser;

        Storyboard storyboard = new Storyboard();
        TimeSpan duration = new TimeSpan(0, 0, 0, 0, 600);
        DoubleAnimation animation = new DoubleAnimation();
        animation.From = 1.0;
        animation.To = 0.0;
        animation.Duration = new Duration(duration);

        Storyboard.SetTargetName(animation, "overlayControl");
        Storyboard.SetTargetProperty(animation, new PropertyPath(Control.OpacityProperty));
        storyboard.Children.Add(animation);
        storyboard.Completed += storyboard_Completed;
        storyboard.Begin(this);
    }

    void ServiceClient_AuthorizationFailed(SMServiceEventArgs args)
    {
        loginErrorBlock.Text = args.message;
    }

    private void LoginForm_LoginButtonClicked(object sender, RoutedEventArgs e)
    {
        _viewModel.AuthUser();
    }

    void storyboard_Completed(object sender, EventArgs e)
    {
        overlayControl.Visibility = System.Windows.Visibility.Collapsed;
    }
}

和Xaml:

<controls:MetroWindow x:Class="ScheduleManager.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sm="clr-namespace:ScheduleManager"
        xmlns:controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
        xmlns:extWpf="clr-namespace:Xceed.Wpf.Toolkit;assembly=Xceed.Wpf.Toolkit"
        Title="Schedule Manager" Height="500" Width="600" MinHeight="500" MinWidth="600">
    <Grid x:Name="mainGrid">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid x:Name="overlayThrobber" Grid.Column="1" Grid.Row="1" Background="Gray" Opacity="0.7" Panel.ZIndex="2000" Visibility="Collapsed">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <controls:ProgressRing x:Name="processThrobber" Grid.Column="1" Grid.Row="1" Foreground="White" IsActive="True" Opacity="1.0"/>
        </Grid>
    </Grid>
</controls:MetroWindow>

整個過程從調用LoginForm_LoginButtonClicked開始。

我想在SMServiceClient發送數據請求時顯示overlayThrobber 我嘗試了很多方法來異步顯示它,例如通過Dispatcher.Invoke和Dispatcher.BeginInvoke或創建新的Thread,但沒有任何效果。 我需要從RequestStarted和RequestFinished事件的處理程序中顯示/隱藏overlayThrobber 也許它不起作用,因為我試圖調用在SMServiceClient的處理程序中顯示overlayThrobber的功能? 你能給我什么建議?

羅馬,

我通常在這里建議在視圖模型上使用一個屬性,該屬性連接“ overlayThrobber”元素的可見性。 然后,您可以更改此值,並且UI將自動更新-這使用的是稱為MVVM(模型-視圖-視圖模型)的標准XAML范例。

“視圖”是XAML。 它使用數據綁定來綁定到ViewModel(在本例中為您的代碼)。 模型通常是后端,在這種情況下,您可以將通過網絡檢索的數據視為模型。

因此,在這種情況下,您將在視圖模型上公開一個屬性,我們將其稱為ThrobberVisible ...

私人布爾值_throbberVisible;

public bool ThrobberVisible
{
  get { return _throbberVisible; }
  set
  {
    if (value != _throbberVisible)
    {
      _throbberVisible = value;
      this.OnPropertyChanged("ThrobberVisible");
    }
  }
}

這還取決於您還在View Model類上創建OnPropertyChanged方法...

protected void OnPropertyChanged(string propertyName)
{
  var handler = this.PropertyChanged;
  if (null != handler)
    handler(this, new PropertyChangedEventArgs(propertyName));
}

此代碼引發屬性更改通知,這是UI會監聽的內容。 有許多UI框架可以實現這種玩法。 我使用了一堆好伴侶和XAML專家Josh的片段。

現在,您需要更改XAML,以便將rob動者的可見性與ThrobberVisible值綁定在一起。 通常,您將執行以下操作...

... Visibility={Binding ThrobberVisible, Converter={StaticResource boolToVisible}}

這將可見性與視圖模型上的屬性掛鈎。 然后,你需要一個轉換器從布爾真/假值轉換為可見XAML /折疊的價值,比如這個類。 您將定義一個靜態資源作為此布爾轉換器,通常在App.Xaml文件中執行此操作,因為我在各處都使用此轉換器。

一切就緒之后,您現在只需更改視圖模型上的布爾值,就可以翻轉UI元素的可見性。

希望這可以幫助! 抱歉,如果代碼無法編譯,我只是徒手輸入。 :-)

您所做的一切都是正確的,但是您使用Threads Dispatcher而不是UI Dispatcher來更新UI。 您可以執行以下操作以從另一個線程更新UI。 這不僅與可視性有關,如果要從另一個線程執行任何類型的UI操作,也必須執行相同的操作。 在您的MainWindow.Xmal.cs中聲明一個如下所示的本地調度程序並使用它

public partial class MainWindow : MetroWindow
{
 public ViewModel _viewModel;
 private  Dispatcher dispathcer = Dispatcher.CurrentDispatcher;
 public MainWindow()
 {
    InitializeComponent();
    _viewModel = new ViewModel();
    _viewModel.client.AuthorizationSucceeded += ServiceClient_AuthorizationSucceeded;
    _viewModel.client.AuthorizationFailed += ServiceClient_AuthorizationFailed;
    _viewModel.client.RequestStarted += ServiceClient_RequestStarted;
    _viewModel.client.RequestFinished += ServiceClient_RequestFinished;

    this.DataContext = _viewModel;
}

void ServiceClient_RequestStarted(SMServiceEventArgs args)
{
   dispathcer.Invoke(new Action(() => { overlayThrobber.Visibility = System.Windows.Visibility.Visible; }), DispatcherPriority.Normal);
}

void ServiceClient_RequestFinished(SMServiceEventArgs args)
{
    dispathcer.Invoke(new Action(() => { overlayThrobber.Visibility = System.Windows.Visibility.Collapsed; }), DispatcherPriority.Normal);
}

暫無
暫無

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

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