2017-07-20 29 views
0

調用用戶控件的公共方法,我在C#MVVM WPF應用程序,.NET 3.5和Visual Studio 2008WPF用戶控件:從視圖模型

從APP主XAML我導入用戶控制。

這個用戶控件具有一些公共方法,有兩個我很感興趣。

一種方法來啓動動畫,另一個阻止它。

從代碼隱藏(xaml.cs)中我的視圖的構造函數,我調用用戶控件公共方法來啓動動畫,以顯示給用戶,而我在ListView中加載一些數據到我的gridview。加載數據的方法稱爲窗體我的視圖模型。

所以,現在,當加載任務完成後,我需要調用另一個用戶控制公共方法來停止動畫,但我不知道如何從我的視圖模型做到這一點。

任何想法?我不能觸摸用戶控件,因爲這不是我的。

下面的一段代碼。

XAML

xmlns:controlProgress="clr-namespace:Common.XAML.Controls.Progress;assembly=Common.XAML" 

<controlProgress:Progress x:Name="Progress" 
         Grid.ZIndex="3" 
         HorizontalAlignment="Center" 
         VerticalAlignment="Center" 
         Width="150" 
         CustomText="Loading..."> 

代碼隱藏(xaml.cs):

public MyView(ViewModelSession vm) 
     : base(vm) 
    {    
     InitializeComponent(); 

     Progress.StartAnimation(); 
    } 

視圖模型:

public MyViewModel(Session session) 
     : base(session) 
    {    
     this.LoadDataIntoGridView(); 
    } 
+1

「我不能觸摸用戶控制,因爲這不是我的。」那麼你是不幸的,因爲視圖模型沒有引用視圖,所以它不能直接調用它的任何方法。 – mm8

+0

我剛剛發佈我的答案,當看到那個邪惡的線......我立即刪除 .. – taquion

+0

包裹UC,你不能在UC你可以觸摸。然後將您的VM綁定到外部UC。您可以從外部UC代碼隱藏中對虛擬機中的狀態變化做出反應,並根據需要對包裝的UC執行任何操作。顯示它,隱藏它,調用它的方法,把它打在臉上,不管。 – Will

回答

3

您可以使用例如INotifyPropertyChanged接口。創建ViewModelBase

public class ViewModelBase 
    : INotifyPropertyChanged 
{  
    public event PropertyChangedEventHandler PropertyChanged; 

    private void OnPropertyChanged([CallerMemberName] String propertyName = "") 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 

然後你用這個你視圖模型,並添加屬性IsLoading

public class MyViewModel : ViewModelBase 
{    
    private bool _isLoading; 

    public bool IsLoading 
    { 
     get { return _isLoading; } 
     set 
     { 
     if(_isLoading == value) return; 
     _isLoading = value; 
     OnPropertyChanged(); 
     } 
} 

然後在您查看代碼隱藏使用視圖模型的PropertyChanged事件開始/停止動畫。

然後你可以設置布爾在你的ViewModel啓動,停止收盤動畫 在你看來

UPDATE

public class MyView 
{ 
    private readonly MyViewModel _viewModel; 

    public MyView(MyViewModel viewModel) 
      : base(viewModel) 
    { 
     InitializeComponent(); 
     _viewModel = viewModel; 
     _viewModel.PropertyChanged +=OnPropertyChanged; 
    } 

    private void OnPropertyChanged(object sender, PropertyChangedEventArgs e) 
    { 
     if (e.PropertyName == nameof(MyViewModel.IsLoading)) 
     { 
      if (_viewModel.IsLoading) 
      { 
       Progress.StartAnimation(); 
      } 
      else 
      { 
       Progress.StopAnimation(); 
      } 
     } 
    } 
} 
+1

「我不能觸摸用戶控件,因爲這不是我的。」... – taquion

+0

我認爲他意味着他不能觸摸controlProgress用戶控件 – Mainpat

+0

這可能是有道理的,在這種情況下,它是可能的。然而,**新的MyViewModel()。PropertyChanged + = OnPropertyChanged; **是不正確的,但** _ viewModel.PropertyChanged + = OnPropertyChanged; ** – taquion

0

你可以把一個布爾在您的視圖模型中使用屬性來跟蹤加載是否已完成,然後該屬性將設置爲true。

public class MyViewModel 
    { 

     public bool IsLoadComplete { get; set; } 
     public MyViewModel() 
     { 
      this.LoadDataIntoGridView(); 
     } 
    } 

然後在你的代碼隱藏你就可以開始任務,以跟蹤的DataContext的該屬性變化:

public MyView(MyViewModel vm) 
     { 
      InitializeComponent(); 

      Progress.StartAnimation(); 

      Task.Run(() => 
      { 
       var dataContext = DataContext as MyViewModel; 
       while (true) 
       { 
        if (dataContext.IsLoadComplete) 
         break; 
        Task.Delay(100); 
       } 
       Dispatcher.BeginInvoke(new Action(() => { Progress.StopAnimation(); })); 
      }); 
     } 

你必須使用Dispatcher.BeginInvoke排隊在UI線程調用。當然,這不是一個現成的解決方案。您可以提供Datacontext直到View被構建,在這種情況下您必須重構,並且您可以跟蹤剛開始的任務,並且可以通過CancellationToken取消支持。這只是一個樣本