C# 如何从视图模型(.cs)调用窗口(.xaml.cs)中的方法而不在 wpf 中引入新的引用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19847860/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 15:59:30  来源:igfitidea点击:

How to call method in window (.xaml.cs) from viewmodel (.cs) without introducing new references in wpf

c#wpfmvvmviewmodel

提问by

I'm looking for a simple way to call a method in my Main Window, but I want to call it from my View Model. Basically, I'm looking for some king of "this.parent" sort of thing to put in the View Model to reference the Main Window.

我正在寻找一种在主窗口中调用方法的简单方法,但我想从我的视图模型中调用它。基本上,我正在寻找某种“this.parent”之类的东西来放入视图模型以引用主窗口。

Or, if you want to check out the reason I want to do this and tell me another way to go about my problem:

或者,如果您想查看我想这样做的原因,并告诉我另一种解决问题的方法:

I'm working with an app that constantly gets information fed to it. In the viewmodel, the information is processed. I want to make a notification every time a piece of information comes in that satisfies some qualification.

我正在使用一个不断获取信息的应用程序。在视图模型中,信息被处理。每当有满足某种条件的信息进入时,我都想发出通知。

Initially, I had a dictionary in the viewmodel that stored info about that information, and I accessed that dictionary in the MainWindow so that I could make the window flash and send other notifications. But I was getting issues with the viewmodel's dictionary being continuously changed while I was accessing it in the MainWindow.

最初,我在视图模型中有一个存储有关该信息的信息的字典,我在 MainWindow 中访问了该字典,以便我可以使窗口闪烁并发送其他通知。但是当我在 MainWindow 中访问视图模型的字典时,我遇到了不断变化的问题。

Sorry if this question sounds stupid. I just started with WPF two months ago, and didn't have a great background in programming even before that, either.

对不起,如果这个问题听起来很愚蠢。我两个月前才开始使用 WPF,在此之前也没有很好的编程背景。

采纳答案by Dean Kuga

VM should "know" nothing of your View or Window, the way VM typically "communicates" with V in WPF/MVVM is by rasing events. That way VM remains ignorant of/decoupled from the V and since VM is already DataContextof V it's not hard to subscribe to VM's event.

VM 应该“不知道”您的视图或窗口,VM 通常与 WPF/MVVM 中的 V“通信”的方式是通过引发事件。这样 VM 仍然不了解 V/与 V 分离,并且由于 VM 已经DataContext是 V,因此订阅 VM 的事件并不难。

Example:

例子:

VM:

虚拟机:

public event EventHandler<NotificationEventArgs<string>> DoSomething;
...
Notify(DoSomething, new NotificationEventArgs<string>("Message"));

V:

五:

var vm = DataContext as SomeViewModel; //Get VM from view's DataContext
if (vm == null) return; //Check if conversion succeeded
vm.DoSomething += DoSomething; // Subscribe to event

private void DoSomething(object sender, NotificationEventArgs<string> e)
{
    // Code    
}

回答by Lance

first of all, it's not a stupid question. Most of MVVM starters came from winforms and it's normal to have the tendency to bring in your winforms practices and work on code behind. Now all you have to do is forget that and think MVVM.

首先,这不是一个愚蠢的问题。大多数 MVVM 初学者都来自 winforms,并且倾向于引入你的 winforms 实践并处理代码背后的工作是正常的。现在你所要做的就是忘记这一点并考虑 MVVM。

Going back to your question, you have a dictionary that your VM is processing and you are accessing that dictionary from the view. Your view should not have any idea about your viewmodel except through binding.

回到您的问题,您有一个 VM 正在处理的字典,并且您正在从视图访问该字典。除了通过绑定之外,您的视图不应该对您的视图模型有任何了解。

Making a window flash when there are changes in the viewmodel sounds like an attached behavior to me. Here's a good read about attached behavior. http://www.codeproject.com/Articles/28959/Introduction-to-Attached-Behaviors-in-WPF

当视图模型发生变化时让窗口闪烁对我来说听起来像是附加行为。这是有关附加行为的好读物。 http://www.codeproject.com/Articles/28959/Introduction-to-Attached-Behaviors-in-WPF

To make it easier, I'll try to give you a very simple example that will somehow be relevant to your case.

为方便起见,我将尝试为您提供一个非常简单的示例,该示例以某种方式与您的案例相关。

Create an attached behavior class where you have an IEnumerable where in whenever you add something a messagebox will appear on the screen. Just change the messagebox code to whatever flashing animation you would like to do on notify.

创建一个附加的行为类,其中有一个 IEnumerable,每当您添加内容时,屏幕上都会出现一个消息框。只需将消息框代码更改为您想要在通知时执行的任何闪烁动画。

public class FlashNotificationBehavior
{
    public static readonly DependencyProperty FlashNotificationsProperty =
        DependencyProperty.RegisterAttached(
        "FlashNotifications",
        typeof(IEnumerable),
        typeof(FlashNotificationBehavior),
        new UIPropertyMetadata(null, OnFlashNotificationsChange));

    private static void OnFlashNotificationsChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var collection = e.NewValue as INotifyCollectionChanged;

        collection.CollectionChanged += (sender, args) => 
            {
                if (args.Action == NotifyCollectionChangedAction.Add)
                {
                    foreach (var items in args.NewItems)
                        MessageBox.Show(items.ToString());
                }
            };            
    }

    public static IEnumerable GetFlashNotifications(DependencyObject d)
    {
        return (IEnumerable)d.GetValue(FlashNotificationsProperty);
    }

    public static void SetFlashNotifications(DependencyObject d, IEnumerable value)
    {
        d.SetValue(FlashNotificationsProperty, value);
    }
}

In your viewmodel, you can create an ObservableCollection property, you need an observable collection so there is a collection changed event notification. I also added a command for adding so that you can test it.

在您的视图模型中,您可以创建一个 ObservableCollection 属性,您需要一个可观察的集合,以便有一个集合更改事件通知。我还添加了一个用于添加的命令,以便您可以对其进行测试。

   public class MainViewModel : ViewModelBase
{
    ObservableCollection<string> notifications;

    public ObservableCollection<string> Notifications
    {
        get { return notifications; }
        set
        {
            if (notifications != value)
            {
                notifications = value;
                base.RaisePropertyChanged(() => this.Notifications);
            }
        }
    }

    public ICommand AddCommand
    {
        get
        {
            return new RelayCommand(() => this.Notifications.Add("Hello World"));
        }
    }

    public MainViewModel()
    {
        this.Notifications = new ObservableCollection<string>();             
    }
}

And here's a view where you can bind it the Notifications proeprty from your view model.

这是一个视图,您可以在其中将其绑定到您的视图模型中的 Notifications 属性。

<Window x:Class="WpfApplication7.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:vm="clr-namespace:WpfApplication7.ViewModel"
    xmlns:local="clr-namespace:WpfApplication7"
    Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
    <vm:MainViewModel />
</Window.DataContext>
<Grid>
    <StackPanel>
        <ListBox ItemsSource="{Binding Notifications}" 
                 local:FlashNotificationBehavior.FlashNotifications="{Binding Notifications}"></ListBox>
        <Button Command="{Binding AddCommand}" >Add Something</Button>
    </StackPanel>
</Grid>

Everytime you add something in the ObservableCollection, you will get a messagebox notifying the user that something has been added to your collection.

每次在 ObservableCollection 中添加内容时,您都会收到一个消息框,通知用户某些内容已添加到您的集合中。

I hope that I helped in your problem. Just tell me if you need some clarifications.

我希望我对你的问题有所帮助。如果您需要一些说明,请告诉我。