C# 导入图像MVVM WPF

C# 导入图像MVVM WPF,c#,wpf,xaml,mvvm,C#,Wpf,Xaml,Mvvm,我是WPF的新手,在尝试学习WPF的过程中,我遇到了MVVM框架。现在我正试图用一个简单的应用程序来实现它,这个应用程序导入并显示一个图像 XAML: 代码隐藏: using Microsoft.Win32; using System; using System.Windows; using System.Windows.Media.Imaging; namespace mvvmSample { /// <summary> /// Interaction logic for Mai

我是WPF的新手,在尝试学习WPF的过程中,我遇到了MVVM框架。现在我正试图用一个简单的应用程序来实现它,这个应用程序导入并显示一个图像

XAML:

代码隐藏:

using Microsoft.Win32;
using System;
using System.Windows;
using System.Windows.Media.Imaging;

namespace mvvmSample
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }


    private void Button_Click(object sender, RoutedEventArgs e)
    {
        OpenFileDialog open = new OpenFileDialog();
        open.DefaultExt = (".png");
        open.Filter = "Pictures (*.jpg;*.gif;*.png)|*.jpg;*.gif;*.png";

        if (open.ShowDialog() == true)
            _image.Source = new BitmapImage(new Uri(open.FileName));
      }
   }
}
我看了很多关于mvvm初学者的教程,读了很多关于mvvm的文章,我掌握了mvvm背后的概念。对于我的应用程序,我假设视图与我的视图相同,但不使用事件,而是对源和按钮使用命令绑定。对于模型,我假设我应该有一个image属性,但我不确定它应该获取并设置文件路径还是图像本身。视图模型将包含图像检索OpenFileDialog和按钮命令的函数。我的假设是否正确,或者是否有更好的方法将此应用程序转换为mvvm。一个样本编码将是伟大的,所以我可以分析它


提前感谢,

在ViewModel中,您应该定义单击按钮时要执行的逻辑。为此,需要使用命令。我的建议是使用a,这是一个通用命令:

public class RelayCommand : ICommand
{
    #region Fields

    readonly Action<object> _execute;
    readonly Predicate<object> _canExecute;

    #endregion // Fields

    #region Constructors

    public RelayCommand(Action<object> execute)
        : this(execute, null)
    {
    }

    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");

        _execute = execute;
        _canExecute = canExecute;
    }
    #endregion // Constructors

    #region ICommand Members

    //[DebuggerStepThrough]
    /// <summary>
    /// Defines if the current command can be executed or not
    /// </summary>
    /// <param name="parameter"></param>
    /// <returns></returns>
    public bool CanExecute(object parameter)
    {
        return _canExecute == null || _canExecute(parameter);
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public void Execute(object parameter)
    {
        _execute(parameter);
    }

    #endregion // ICommand Members
}
使用此ViewModel,您不需要在视图的代码开头执行任何操作。您只需在窗口的资源中实例化ViewModel,并设置根网格的DataContext属性。之后,可以使用适当的控件绑定属性和命令:

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:wpfApplication1="clr-namespace:WpfApplication1"
    Title="MainWindow" Width="1024" Height="768">
<Window.Resources>
    <wpfApplication1:MainViewModel x:Key="MainViewModel"/>
</Window.Resources>
<Grid DataContext="{StaticResource MainViewModel}">
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition Height="auto"/>
    </Grid.RowDefinitions>
    <GroupBox Grid.Row="0" Header="Imported Picture">
        <Image x:Name="_image" Stretch="Fill" Source="{Binding ImagePath}"/>
    </GroupBox>
    <Button Height="50" Grid.Row="1" Content="Import Picture" Command="{Binding LoadImageCommand}"  />
</Grid>
八氯乙烯

我确实在编码中使用了自己的名称空间,因此:

<Window x:Class="mvvmSample.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mvvmSample="clr-namespace:mvvmSample"
    xmlns:vm="clr-namespace:mvvmSample.ViewModel"
    Title="MainWindow" Width="1024" Height="768">
<Window.Resources>
    <vm:MainViewModel x:Key="MainViewModel"/>
</Window.Resources>
<Grid DataContext="{StaticResource MainViewModel}">
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition Height="auto"/>
    </Grid.RowDefinitions>
    <GroupBox Grid.Row="0" Header="Imported Picture">
        <Image x:Name="_image" Stretch="Fill" Source="{Binding ImagePath}" />
    </GroupBox>
    <Button Height="50" Grid.Row="1" Content="Import Picture" Command="{Binding LoadedImageCommand}"/>
</Grid>
我添加了后者,因为我无法在窗口中访问MainViewModel。没有它的资源和mvvmSample只能选择应用程序。该程序运行,但它不做任何事情,它只是显示用户界面,如果我点击按钮,什么也不会发生。我在几个地方放置了断点,比如在RelayCommand和MainWindow代码中,以便能够观察问题,但它只是初始化组件并显示UI

更新:


我能解决这个问题,这完全是我的错。我在绑定中写了错误的函数名,而不是LoadImage我已经加载了Image,这就是为什么我的按钮单击没有激活DUH。谢谢你的帮助。

谢谢你的回复。所以我猜如果我实现其他按钮,比如缩放和保存,我可以使用通用类relaycommand,但是对于ICommand,有可能使它也通用吗?此外,我认为我需要在其中添加ViewModel名称空间,这样我就可以调用它,如果这是正确的措辞,将其用作窗口资源,因为我尝试使用它,而wpfApplication1仅显示应用程序,而不显示主ViewModel。是的,当需要定义您提到的其中一个事件时,您可以使用RelayCommand。我在回答中显示的名称空间是我在应用程序中定义ViewModel的名称空间,因此,您需要自己更改它;视图模型作为视图的资源是一种可怕的模式。我建议您使用NInject或Autofac或类似工具实现依赖项注入。相信我,如果你选择Caliburn.Micro这样一个像样的框架,你会更喜欢MVVM。
<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:wpfApplication1="clr-namespace:WpfApplication1"
    Title="MainWindow" Width="1024" Height="768">
<Window.Resources>
    <wpfApplication1:MainViewModel x:Key="MainViewModel"/>
</Window.Resources>
<Grid DataContext="{StaticResource MainViewModel}">
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition Height="auto"/>
    </Grid.RowDefinitions>
    <GroupBox Grid.Row="0" Header="Imported Picture">
        <Image x:Name="_image" Stretch="Fill" Source="{Binding ImagePath}"/>
    </GroupBox>
    <Button Height="50" Grid.Row="1" Content="Import Picture" Command="{Binding LoadImageCommand}"  />
</Grid>
<Window x:Class="mvvmSample.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mvvmSample="clr-namespace:mvvmSample"
    xmlns:vm="clr-namespace:mvvmSample.ViewModel"
    Title="MainWindow" Width="1024" Height="768">
<Window.Resources>
    <vm:MainViewModel x:Key="MainViewModel"/>
</Window.Resources>
<Grid DataContext="{StaticResource MainViewModel}">
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition Height="auto"/>
    </Grid.RowDefinitions>
    <GroupBox Grid.Row="0" Header="Imported Picture">
        <Image x:Name="_image" Stretch="Fill" Source="{Binding ImagePath}" />
    </GroupBox>
    <Button Height="50" Grid.Row="1" Content="Import Picture" Command="{Binding LoadedImageCommand}"/>
</Grid>
xmlns:mvvmSample="clr-namespace:mvvmSample"
xmlns:vm="clr-namespace:mvvmSample.ViewModel"