2017-07-20 106 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取消支持。这只是一个样本

相关问题