【问题标题】:How can I access my ViewModel from code behind如何从后面的代码访问我的 ViewModel
【发布时间】:2020-12-23 23:18:34
【问题描述】:

我不明白如何创建命令来创建 MVVM 可点击矩形。这是我的代码:

<Rectangle x:Name="Color01" Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="100" Margin="10,29,0,0" Stroke="Black" VerticalAlignment="Top" Width="100" MouseDown="Color_MouseDown" />
<Rectangle x:Name="Color02" Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="100" Margin="115,29,0,0" Stroke="Black" VerticalAlignment="Top" Width="100"/>
<Rectangle x:Name="Color03" Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="100" Margin="220,29,0,0" Stroke="Black" VerticalAlignment="Top" Width="100"/>
<Rectangle x:Name="Color04" Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="100" Margin="325,29,0,0" Stroke="Black" VerticalAlignment="Top" Width="100"/>

在我的第一个矩形上,您可以看到我在事件后面创建了一个代码。首先,我不知道如何从后面的代码中访问我的 ViewModel。二这不是真正的 MVVM。

public partial class MainWindow : Window
{
    /// <summary>
    /// Initializes a new instance of the MainWindow class.
    /// </summary>
    public MainWindow()
    {
        InitializeComponent();
        Closing += (s, e) => ViewModelLocator.Cleanup();
    }

    private void Color_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        // So what ???
    }
}

当有人单击我的矩形时,我只需要能够更改存储在我的 viewModel 中存储的列表中的简单布尔值。为什么用 MVVM 做起来这么复杂?

【问题讨论】:

  • var rect = sender as Rectangle 然后做任何你想做的事,虽然这是一个非常糟糕的设计,你应该使用数据绑定并将颜色绑定到一个字段而不是而不是这样做。学习和利用您所获得的抽象概念,而不是与它们抗争。
  • 我得到了这个矩形......那么接下来呢?获取发件人不是问题。之后,我需要更新存储在 viewModel 中的列表中的布尔值。

标签: c# wpf mvvm


【解决方案1】:

在 MVVM 中,您不应该从后面的代码访问您的视图模型,视图模型和视图彼此不知道,因此讲座结束 :)

相反,您可以将 EventToCommand 行为附加到您的控件。这使您可以将控件中的事件绑定到数据上下文中的命令。请在此处查看msdn commands tutorial

如果您迫切需要这样做,您可以访问控件数据上下文属性并将其转换为您的视图模型类型以提供对内部的访问权限。

var vm = (ViewModelType)this.DataContext;
vm.CommandProperty.Execute(null);

【讨论】:

  • 嗨 kidsshaw,你有什么好的资源可以将 ViewModel 和代码隐藏分开吗?我现在正在开发一个代码隐藏,它通过一个属性与 ViewModel 耦合。我知道这并不理想,但是对于我需要的 ViewModel.Method、View.Method、ViewModel.Method 的执行顺序来说,这是不可避免的。
  • @Chucky - 因为那是 MVVM 模式。如果您在其后面引入代码,则应仅补充视图而不访问视图模型。这对于您的应用程序可能不值得,但您通常可以找到一种方法来使用 DataTriggers、EventToCommand 和自定义行为来保持模式。如果您对此感兴趣,请发布您的问题。
  • 这并不完全正确。由于您将 DataContext 属性设置为指向 View 中的 ViewModel,因此它们是绑定的。此外,所有Binding-s 都再次知道 ViewModel 中定义的属性。所以 View 总是知道 ViewModel。然而,相反的情况是不正确的:ViewModel 永远不应该绑定到 View。
【解决方案2】:

快速回答。这也可能对其他人有所帮助

((MyViewModel)(this.DataContext)).MyProperty

【讨论】:

  • DataContext 更改为 BindingContext 对我有用。
【解决方案3】:

这并不难。首先,在 Window XAML 中创建 ViewModel 的实例:

查看 XAML:

<Window x:Class="BuildAssistantUI.BuildAssistantWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:VM="clr-namespace:MySolutiom.ViewModels">
     <Window.DataContext>
         <VM:MainViewModel />
     </Window.DataContext>
  </Window>

之后,您可以System.Windows.Interactivity.InvokeCommandAction 将您的事件转换为命令:

查看 XAML:

<Grid>
 <Rectangle x:Name="Color01" Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="100" Margin="10,29,0,0" Stroke="Black" VerticalAlignment="Top" Width="100" MouseDown="Color_MouseDown">
   <interactivity:Interaction.Triggers>
      <interactivity:EventTrigger EventName="MouseDown">
          <interactivity:InvokeCommandAction Command="{Binding MyCommand}"/>
      </interactivity:EventTrigger>
   </interactivity:Interaction.Triggers>
 </Rectangle>
</Grid>

现在,在您的 ViewModel 中,设置 ICommandDelegateCommand 实现以绑定到该事件:

视图模型:

public class ViewModel
{
    public ICommand MyCommand { get; set; }

    public ViewModel()
    {
        MyCommand = new DelegateCommand(OnRectangleClicked);
    }

    public void OnRectangleClicked()
    {
        // Change boolean here
    }
}

【讨论】:

    【解决方案4】:

    在 C# XAML UWP MVVM 上下文中。

    考虑以下示例

    型号:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace FrostyTheSnowman.Models
    {
        public class User
        {
            public int Id { get; set; }
            public string FirstName { get; set; }
            public string LastName { get; set; }        
    
            public override string ToString() => $"{FirstName} {LastName}";
    
        }
    }
    

    视图模型

    using FrostyTheSnowman.Models;
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace FrostyTheSnowman
    {
        public class MainPageViewModel
        {
            public User user { get; set; }
    
            public MainPageViewModel()
            {
                user = new User
                {
                    FirstName = "Frosty",
                    LastName = "The Snowman"                
                };
            }
        }
    }
    

    查看

    <Page
        x:Class="FrostyTheSnowman.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:FrostyTheSnowman"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    
        <Page.DataContext>
            <local:MainPageViewModel x:Name="ViewModel" />
        </Page.DataContext>
    
        <Grid>
            <StackPanel Name="sp1" DataContext="{Binding user}">
    
                <TextBox Name="txtFirstName"                     
                     Header="First Name"
                     Text="{Binding FirstName}" />
    
                <TextBox Name="txtLastName"                     
                     Header="Last Name"
                     Text="{Binding LastName}" />
    
    
            </StackPanel>
    
        </Grid>
    </Page>
    

    代码隐藏文件:

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Runtime.InteropServices.WindowsRuntime;
    using Windows.Foundation;
    using Windows.Foundation.Collections;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Controls.Primitives;
    using Windows.UI.Xaml.Data;
    using Windows.UI.Xaml.Input;
    using Windows.UI.Xaml.Media;
    using Windows.UI.Xaml.Navigation;
    
    // The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
    
    namespace FrostyTheSnowman
    {
        /// <summary>
        /// An empty page that can be used on its own or navigated to within a Frame.
        /// </summary>
        public sealed partial class MainPage : Page
        {
            MainPageViewModel vm;
    
            public MainPage()
            {
                this.InitializeComponent();
    
                // Initialize the View Model Object
                vm = (MainPageViewModel)this.DataContext;
    
                System.Diagnostics.Debug.WriteLine(vm.user.ToString() + " was a jolly happy soul");
            }
        }
    }
    

    当你运行应用程序时,你会看到:

    但更重要的是,调试跟踪会显示:

    说明后台代码确实成功访问了ViewModel...

    希望对你有帮助

    【讨论】:

    • 现在我的脑海里萦绕着“Frosty The Snowman”这首歌。太好了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-03-22
    • 1970-01-01
    • 1970-01-01
    • 2023-03-17
    • 1970-01-01
    • 2017-02-09
    • 1970-01-01
    相关资源
    最近更新 更多