导入图像 MVVM WPF
Importing Image MVVM WPF
我是 WPF 新手,在尝试学习它时遇到了 MVVM 框架。现在,我正在尝试使用我制作的导入和显示图像的简单应用程序来实现它。
XAML:
<Window x:Class="mvvmSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Width="1024" Height="768">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<GroupBox Grid.Row="0" Header="Imported Picture">
<Image x:Name="_image" Stretch="Fill"/>
</GroupBox>
<Button Height="50" Grid.Row="1" Content="Import Picture" Click="Button_Click"/>
</Grid>
</Window>
隐藏代码:
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 初学者的教程,阅读了很多关于它的文章,我掌握了它背后的概念。对于我的应用程序,我假设视图与我所拥有的相同,但不使用事件,而是对源和按钮使用命令绑定。对于模型,我假设我应该有一个图像 属性 但我不确定它是否应该获取并设置文件路径或图像本身。然后,视图模型将包含用于图像检索 (OpenFileDialog) 和按钮命令的函数。我的假设是否正确,或者是否有更好的方法将此应用程序转换为 mvvm。示例编码会很棒,所以我可以对其进行分析。
提前致谢,
在 ViewModel 中,您应该定义单击按钮时要执行的逻辑。为此,您需要使用一个命令。我的建议是使用 RelayCommand
,这是一个通用命令:
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
}
假设您正在使用上面定义的 RelayCommand
,您需要为其提供一个或两个委托,其中一个是 returns 一个布尔值,用于确定命令是否处于有效状态是 运行,第二个 returns 什么都没有,实际上 运行 是命令。如果您不提供 CanExecute
委托,则该命令将认为它始终处于有效状态。
在您的 ViewModel 中,您还需要一个 属性 来保存图像路径。此 属性 将与您在视图中拥有的 Image
的 Source
属性 绑定。所以,你的 ViewModel class 会是这样的:
public class MainViewModel: INotifyPropertyChanged
{
private string imagePath;
public string ImagePath
{
get { return imagePath; }
set
{
imagePath = value;
SetPropertyChanged("ImagePath");
}
}
ICommand _loadImageCommand;
public ICommand LoadImageCommand
{
get
{
if (_loadImageCommand == null)
{
_loadImageCommand = new RelayCommand(param => LoadImage());
}
return _loadImageCommand;
}
}
private void LoadImage()
{
OpenFileDialog open = new OpenFileDialog();
open.DefaultExt = (".png");
open.Filter = "Pictures (*.jpg;*.gif;*.png)|*.jpg;*.gif;*.png";
if (open.ShowDialog() == true)
ImagePath = open.FileName;
}
#region Property Changed Event Handler
protected void SetPropertyChanged(string propertyName)
{
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion Property Changed Event Handler
}
使用此 ViewModel,您无需在视图的代码开头执行任何操作。您只需在 window 的资源中实例化您的 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>
致 Octavioccl
我在编码中确实使用了自己的命名空间:
<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"
我添加了后者,因为没有它我无法访问 Window.Resources 中的 MainViewModel,而 mvvmSample 只有 App 作为选择。该程序运行但它不执行任何操作它只显示 UI 如果我单击该按钮什么也不会发生。我在后面的 RelayCommand 和 MainWindow 代码等几个地方放置了断点,以便能够观察到问题,但它只是初始化组件并显示 UI.
更新:
我能够解决这个完全是我的错的问题。我在绑定中写错了函数名称而不是 LoadImage 我有 LoadedImage 这就是为什么我的按钮单击没有激活 "DUH"。感谢您的帮助。
我是 WPF 新手,在尝试学习它时遇到了 MVVM 框架。现在,我正在尝试使用我制作的导入和显示图像的简单应用程序来实现它。
XAML:
<Window x:Class="mvvmSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Width="1024" Height="768">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<GroupBox Grid.Row="0" Header="Imported Picture">
<Image x:Name="_image" Stretch="Fill"/>
</GroupBox>
<Button Height="50" Grid.Row="1" Content="Import Picture" Click="Button_Click"/>
</Grid>
</Window>
隐藏代码:
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 初学者的教程,阅读了很多关于它的文章,我掌握了它背后的概念。对于我的应用程序,我假设视图与我所拥有的相同,但不使用事件,而是对源和按钮使用命令绑定。对于模型,我假设我应该有一个图像 属性 但我不确定它是否应该获取并设置文件路径或图像本身。然后,视图模型将包含用于图像检索 (OpenFileDialog) 和按钮命令的函数。我的假设是否正确,或者是否有更好的方法将此应用程序转换为 mvvm。示例编码会很棒,所以我可以对其进行分析。
提前致谢,
在 ViewModel 中,您应该定义单击按钮时要执行的逻辑。为此,您需要使用一个命令。我的建议是使用 RelayCommand
,这是一个通用命令:
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
}
假设您正在使用上面定义的 RelayCommand
,您需要为其提供一个或两个委托,其中一个是 returns 一个布尔值,用于确定命令是否处于有效状态是 运行,第二个 returns 什么都没有,实际上 运行 是命令。如果您不提供 CanExecute
委托,则该命令将认为它始终处于有效状态。
在您的 ViewModel 中,您还需要一个 属性 来保存图像路径。此 属性 将与您在视图中拥有的 Image
的 Source
属性 绑定。所以,你的 ViewModel class 会是这样的:
public class MainViewModel: INotifyPropertyChanged
{
private string imagePath;
public string ImagePath
{
get { return imagePath; }
set
{
imagePath = value;
SetPropertyChanged("ImagePath");
}
}
ICommand _loadImageCommand;
public ICommand LoadImageCommand
{
get
{
if (_loadImageCommand == null)
{
_loadImageCommand = new RelayCommand(param => LoadImage());
}
return _loadImageCommand;
}
}
private void LoadImage()
{
OpenFileDialog open = new OpenFileDialog();
open.DefaultExt = (".png");
open.Filter = "Pictures (*.jpg;*.gif;*.png)|*.jpg;*.gif;*.png";
if (open.ShowDialog() == true)
ImagePath = open.FileName;
}
#region Property Changed Event Handler
protected void SetPropertyChanged(string propertyName)
{
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion Property Changed Event Handler
}
使用此 ViewModel,您无需在视图的代码开头执行任何操作。您只需在 window 的资源中实例化您的 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>
致 Octavioccl
我在编码中确实使用了自己的命名空间:
<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"
我添加了后者,因为没有它我无法访问 Window.Resources 中的 MainViewModel,而 mvvmSample 只有 App 作为选择。该程序运行但它不执行任何操作它只显示 UI 如果我单击该按钮什么也不会发生。我在后面的 RelayCommand 和 MainWindow 代码等几个地方放置了断点,以便能够观察到问题,但它只是初始化组件并显示 UI.
更新:
我能够解决这个完全是我的错的问题。我在绑定中写错了函数名称而不是 LoadImage 我有 LoadedImage 这就是为什么我的按钮单击没有激活 "DUH"。感谢您的帮助。