C# 在视图中调用方法';是ViewModel的代码隐藏吗?

C# 在视图中调用方法';是ViewModel的代码隐藏吗?,c#,wpf,xamarin,mvvm,uwp,C#,Wpf,Xamarin,Mvvm,Uwp,我在视图的代码隐藏中有一个方法(这个方法对我的UI有作用) 无论如何,我想从我的ViewModel触发这个方法。如何做到这一点?根据ViewModel不知道视图,因此这是不可接受的。要与ViewModel视图交互,可以触发命令,也可以使用绑定。此外,您不应该将特定于UI的东西(如BusyIndicator)移动到ViewModel级别 请提供有关您的具体用例的更多详细信息-当您想调用视图的方法时,以及该方法的作用。我看到您在回答上述问题,您是说希望您的ViewModel检索数据,然后告诉您的视图

我在视图的代码隐藏中有一个方法(这个方法对我的UI有作用)

无论如何,我想从我的ViewModel触发这个方法。如何做到这一点?

根据ViewModel不知道视图,因此这是不可接受的。要与ViewModel视图交互,可以触发命令,也可以使用绑定。此外,您不应该将特定于UI的东西(如BusyIndicator)移动到ViewModel级别


请提供有关您的具体用例的更多详细信息-当您想调用视图的方法时,以及该方法的作用。

我看到您在回答上述问题,您是说希望您的ViewModel检索数据,然后告诉您的视图停止忙碌指示灯

我不确定我的解决方案是否是最好的解决方案,但你可以试一试,如果我错了,也许有人可以纠正

从您的观点来看,您应该从ViewModel调用一个方法来开始读取数据集,对吗?在该方法中,您可以传递一个委托(指向视图中存在的方法),当ViewModel从服务器读取完数据集后,触发与视图中的方法链接的委托(来自ViewModel),该委托可以停止忙碌指示器

所以在你看来你有

void StopBusyIndicator()
{
    this.BusyIndicator.IsBusy = false;
}
当调用ViewModel读取数据集时

可以这样称呼:

ViewModel.ReadDataSet( ()= >StopBusyIndicator)
它将以委托的形式传递StopBusyIndicator方法,您可以在ReadDataSet末尾调用该委托


HTH

您可以编写一个接受数据传输对象的操作类。在DTO中,添加一个名为“视图”的属性,并将其指定为当前视图。从视图的codebehind中通过控制器调用操作,取消对DTO的绑定,现在您可以完全控制action类中的视图

如果您真的想在模型中这样做,只需在模型中创建一个带有“视图”类型参数的方法,并执行它,传入当前视图。

My(可能还有其他人?)MVVM的困难在于理解一件简单的事情:视图了解ViewModel。我使用的是绑定和命令,但它们在
xaml
中是简单的
字符串。由于在运行时进行安全解析(安全意味着您可以输入错误,但软件不会崩溃),这使得视图与视图模型解耦(至少在编译时)。我一直在寻找保持这种脱钩的解决方案,比如行为

事实上,您可以直接访问视图模型,它通常是窗口/用户控件的
DataContext

var vm = (MyViewModel)this.DataContext;
要知道,使用事件可能是从视图模型调用view方法的最佳方式,因为视图模型不知道是否有订阅者,它只是触发该事件,并且事件可以由视图或其他视图模型使用

// define in the view model
public delegate void MyEventAction(string someParameter, ...);
public event MyEventAction MyEvent;

// rise event when you need to
MyEvent?.Invoke("123", ...);

// in the view
var vm = (MyViewModel)DataContext;
vm.MyEvent += (someParameter, ...) => ... // do something

您可以在视图中这样做(代码隐藏)

它强制转换到要由ViewModel实现的接口,这样您就不会被约束到一个特定的ViewModel类型

    // CONSTRUCTOR
    public SomeView()
    {
        InitializeComponent();

        DataContextChanged += DataContextChangedHandler;
    }

    void DataContextChangedHandler(object sender, DependencyPropertyChangedEventArgs e)
    {
        var viewModel = e.NewValue as IInterfaceToBeImplementedByViewModel;

        if (viewModel != null)
        {
            viewModel.SomeEvent += (sender, args) => { someMethod(); }
        }
    }

假设您在my Login视图的代码隐藏中有一个方法,如果登录失败,它会通过关注密码条目来更新UI,那么从您的ViewModel触发此方法的最简单和最通用的方法是使用

正如您在中所看到的,您需要添加的全部内容是,您的服务确定登录失败,并且您希望密码条目获得焦点,即ViewModel中的两行代码和视图中的一个操作处理程序

视图模型代码:

  • 事件声明:
    public Action OnLoginFailed{get;set;}
    &
  • 然后,只要在需要时执行这个
    OnLoginFailed?.Invoke(true)
查看代码:

ViewModel.OnLoginFailed = ((obj) =>
{
    PasswordEntry.Focus();
});

我的UI有一个“忙”指示器,只能通过codebehind启动,因为它是从具有此功能的用户控件派生的。因此,我需要viewmodel设置这个忙指示符,因为它是处理从服务器获取数据的指示符。您可以尝试在XAML中声明busynduicator并设置到viewmodel属性的绑定吗?ViewModel应如何准确设置此指示器?能否通过ViewModel显示BudyIndicator初始化代码?此外,您不应该将特定于UI的东西(如BusyIndicator)移动到ViewModel级别。在您的示例中,语法似乎不正确。为了让它工作,我不得不对它做很多修改。@Deantwo,3年前我没有使用太多,也没有从
EventArgs
继承参数。。。目前正在修复明显的打字错误,感谢您的报道。这是一个极好的答案。我必须使用:var vm=(MyViewModel)BindingContext;用于xamarin表单而不是DataContext。非常感谢。很好用。我喜欢DataContextChanged的使用,因为它在稍后设置viewModel时有效,而不是在视图创建期间。