17

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

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

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

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

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

4

2 回答 2

32

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

例子:

虚拟机:

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

五:

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    
}
于 2013-11-07T23:09:38.857 回答
14

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

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

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

为了使它更容易,我将尝试给您一个非常简单的示例,该示例将与您的案例相关。

创建一个附加的行为类,其中您有一个 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);
    }
}

在您的视图模型中,您可以创建一个 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>();             
    }
}

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

<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>

每次你在 ObservableCollection 中添加一些东西时,你都会收到一个消息框,通知用户一些东西已经添加到你的集合中。

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

于 2013-11-08T00:47:41.840 回答