WPF/MVVM 快速开始指南(译)(转)

时间:2022-01-26 05:42:32

本篇文章是Barry Lapthorn创作的,感觉写得很好,翻译一下,做个纪念。由于英文水平实在太烂,所以翻译有错或者译得不好的地方请多指正。另外由于原文是针对WPF的,我在原文的基础上做了一些修改,让例子能在silverlight上运行。

原文链接:http://www.codeproject.com/KB/WPF/WpfMvvmQuickStart.aspx

中文原文:http://www.cnblogs.com/xiaobaihome/archive/2011/11/28/2266536.html

简介

假设你对C++有很好的理解,也对C#有适当的了解,那么准备开始WPF学习将不会太困难。我在六个月前开始着手于WPF,然后可能在谷歌搜索中导致了一个结果,我最后开始明白并且开始使用WPF进行生产(我是否错过了这条船,是另一天的另一个故事了)。

就像学习任何新技术一样,事后你将从中得到益处,在我看来,几乎我所遇到的所有的WPF教程都有以下几个方面的不足:

  • 例子全是WPF里面的
  • 例子缺少关键的注释,事实上你自己制作一个更容易
  • 例子试图炫耀WPF的能力,大量的毫无意义的结果,对你没有任何帮助
  • 例子使用的类名中有些属性似乎和框架关键字或类名太相似,因此很难在xaml代码中作为用户定义的标示符来使用(ListBoxGroupStyle的名称很让初学者头疼)。

为了解决这个问题,基于在谷歌上输入“WPF 教程”得到的第一条结果我写下了这篇文章。这篇文章可能不是100%正确,或者甚至是做事情的“唯一正确的方法”,不管怎么样它将阐明一些主要的点,这些点是我在六个月前希望发现的。

我将快速的介绍一些主题,然后展示一个例子来解释或演示每一个观点。因此,我事实上没有试图使GUI更漂亮,因为这不是这篇文章的要点(参见上面的要点)。

因为这个教程相当长,为了简洁我将省略许多代码,因此请下载附加的ZIP文件,然后看里面的例子(.NET4.0/VS2010)。每一个例子都是建立在前一个例子上的。

基本要素

  1. WPF最给力的就是数据绑定,简单的说,你有一些数据,按照某种特征分类放在一个集合里,然后你想将它显示给用户。你可以将数据“绑定”到xaml代码。
  2. WPF有两个部分,xmal描述你的GUI布局和效果,这个后台代码是绑定到xaml的。
  3. 一种最优雅的和最大可能被复用的方式来组织你的代码的方法是使用"MVVM"模式:模型,视图,视图模型。

你需要知道的关键点

  1. 存储数据你应该使用的集合是ObservableCollection<>。而不是list,也不是dictionary,而是 ObservableCollection。“Observable”这个词在这里是为这种情况提供:WPF窗口需要能观察到你的数据集合。这个集合类实 现了WPF使用的几个接口。
  2. 每一个WPF控件(包括“窗口”)都有一个“DataContext”,集合控件都有一个“ItemsSource”属性用于绑定。
  3. “INotifyPropertyChanged”接口将被广泛的的用于GUI和你的代码之间的通信,当数据有任何改变的时候。

例1:错误的做法

开始的最好方法是从例子开始,我们将从一个song类开始,而不是通常的person类,我们可以将歌曲整理到专辑里面,或者是一个大的集合里,或者按艺术家来整理。一个简单的song类应该会像下面这样:

WPF/MVVM 快速开始指南(译)(转)
 public class Song
{
#region Members
string _artistName;
string _songTitle;
#endregion #region Properties
///<summary>
/// 艺术家名称
///</summary>
public string ArtistName
{
get { return _artistName; }
set { _artistName = value; }
} ///<summary>
/// 歌曲标题
///</summary>
public string SongTitle
{
get { return _songTitle; }
set { _songTitle = value; }
}
#endregion
}
WPF/MVVM 快速开始指南(译)(转)

在WPF术语中,这个叫“模型”,GUI是“视图”。不可思议的是“视图模型”,通过数据绑定将它们绑在一起,它真的是一个很好的适配器能将模型变成某种WPF框架可以使用的东西。所以只是重复一下,这就是“模型”。

自我们创建Song作为引用类型以后,由于副本在内存上很便宜,我们可以非常容易的创建SongViewMode。我们首先需要考虑的是,什么是我们(潜在的)需要显示的?假如我们只关心歌曲的艺术家名称,而不关心歌曲的标题,那么SongViewModel可以向下面这样定义:

WPF/MVVM 快速开始指南(译)(转)
public class SongViewModel
{
Song _song; public Song Song
{
get { return _song; }
set { _song = value; }
} public string ArtistName
{
get { return Song.ArtistName; }
set { Song.ArtistName = value; }
}
}
WPF/MVVM 快速开始指南(译)(转)

只不过这不是十分正确的。由于我们在ViewModel里暴露了一个属性,我们显然会想使在代码里改变的歌曲的艺术家名称自动的显示在GUI上,反之亦然:

SongViewModel song = ...;
//...允许数据绑定...
//改变名称
song.ArtistName = "Elvis";
//gui应该发生改变

请注意,在所有的例子里面,我们都创建了视图模型的“声明”,例如,我们在xaml代码里这样做:

WPF/MVVM 快速开始指南(译)(转)
<UserControl x:Class="Example1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Example1"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400"> <UserControl.DataContext>
<!--声明创建一个SongViewModel的实例-->
<local:SongViewModel/>
</UserControl.DataContext> <Grid x:Name="LayoutRoot" Background="White"> </Grid>
</UserControl>
WPF/MVVM 快速开始指南(译)(转)

这等价于在后台代码MainWindo.cs里这样做:

WPF/MVVM 快速开始指南(译)(转)
    public partial class MainWindow : UserControl
{
SongViewModel _viewModel = new SongViewModel();
public MainWindow()
{
InitializeComponent();
base.DataContext = _viewModel;
}
}
WPF/MVVM 快速开始指南(译)(转)

然后移除xaml中的DataContext元素:

WPF/MVVM 快速开始指南(译)(转)
<UserControl x:Class="Example1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Example1"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400"> <!--无数据上下文-->
WPF/MVVM 快速开始指南(译)(转)

这是运行结果:

WPF/MVVM 快速开始指南(译)(转)

点击更新按钮不会进行任何更新,因为我们没有实现数据绑定。

数据绑定

记得我在一开始说,我会选择一个突出的属性。 在这个例子里,我们想显示艺术家姓名。我选择这个名字是因为它和任何WPF属性都不相同。在网络上有无数的例子,选择一个Person类和他的Name属性(它在多个WPF元素中都存在),也许这些文章的作者只是没有意识到这样对初学者来说特别容易混淆(这些文章的目标读者有足够的好奇心)。

有许多的其它关于数据绑定的文章,因此我不能全部包括他们。我希望这个例子是如此微不足道,以至于你可以看清楚它是怎么回事。

绑定SongViewModel的ArtistName属性,我们可以简单的这么做在MianWindow.xaml中:

<TextBlock Text="{Binding ArtistName}"/>

“绑定”关键字绑定这个控件的Text,在这里这个控件是TextBlock,对“ArtistName”这个属性来说由DataContext返回对象。就像你上面所看到的,我们给DataContext设置了一个SongViewModel实例,因此我们在TextBlock上实际是显示的_songViewModel.ArtistName。

再说一次:点击更新按钮不会进行任何更新,因为我们没有实现数据绑定。GUI不会收到任何的关于属性改变的通知。

例2:INotifyPropertyChanged接口

我们必须实现名称为INotifyPropertyChanged的巧妙接口。就像他说的,任何实现了这个接口的类,当属性发生改变的时候会通知所有监听者,所以我们需要修改SongViewModel类稍微多一点点:

WPF/MVVM 快速开始指南(译)(转)
public class SongViewModel : INotifyPropertyChanged
{ #region 构造函数
/// <summary>
/// 构造缺省的SongViewModel实例
/// </summary>
public SongViewModel()
{
_song = new Song { ArtistName = "Unknown", SongTitle = "Unknown" };
}
#endregion #region 成员
Song _song;
#endregion #region 属性
public Song Song
{
get { return _song; }
set { _song = value; }
} public string ArtistName
{
get { return Song.ArtistName; }
set
{
if (Song.ArtistName != value)
{
Song.ArtistName = value;
RaisePropertyChanged("ArtistName");
}
}
}
#endregion #region INotifyPropertyChanged 成员 public event PropertyChangedEventHandler PropertyChanged; #endregion #region INotifyPropertyChanged 方法
private void RaisePropertyChanged(string propertyName)
{
//得到一个副本以预防线程问题
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
WPF/MVVM 快速开始指南(译)(转)

现在这里有几件事发生了。首先,我们检查了我们是否真的改变了属性:这样对大多数复杂对象来说能稍微提高性能。第二,如果值已经改变,我们向所有监听者注册PropertyChanged事件。

那么现在我们有了一个模型,和一个视图模型。我们只需要在定义视图。只需要修改MainWindow:

WPF/MVVM 快速开始指南(译)(转)
<UserControl x:Class="Example2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Example2"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400"> <UserControl.DataContext>
<!--声明创建一个SongViewModel的实例-->
<local:SongViewModel/>
</UserControl.DataContext> <Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0" Text="例2 - 它能工作!" />
<TextBlock Grid.Column="0" Grid.Row="1" Text="艺术家: " />
<TextBlock Grid.Column="1" Grid.Row="1" Text="{Binding ArtistName}" />
<Button Grid.Column="1" Grid.Row="2" Name="ButtonUpdateArtist" Content="更新艺术家姓名" Click="ButtonUpdateArtist_Click" />
</Grid>
</UserControl>
WPF/MVVM 快速开始指南(译)(转)

为了测试数据绑定,我们可以用传统方法,创建一个按钮然后写上它的OnClick事件,所以上面的xaml有一个按钮,和Click事件,给出后台代码:

WPF/MVVM 快速开始指南(译)(转)
 public partial class MainWindow : UserControl
{
#region 成员
/// <summary>
/// 视图模型
/// </summary>
SongViewModel _viewModel; int _count = 0;
#endregion public MainWindow()
{
InitializeComponent(); //已经在xaml代码中声明了视图模型实例
//在这里拿到它的引用,因此我们可以在按钮click事件里使用它
_viewModel = (SongViewModel)base.DataContext;
} private void ButtonUpdateArtist_Click(object sender, RoutedEventArgs e)
{
++_count;
_viewModel.ArtistName = string.Format("Elvis({0})",_count);
}
}
WPF/MVVM 快速开始指南(译)(转)

这样就OK啦,但是我们不该这样使用WPF:首先,我们在后台代码里添加了“更新艺术家”逻辑。它不应该属于那里。窗口类与打开窗口是关联的。第二个问题是,假如我们想移动在按钮click事件中的逻辑,这将很难控制。例如,制作一个菜单项,那就意味着我们将要剪切,粘贴,然后在多个地方编辑。

这是改进后的视图,现在点击那里能工作了:

WPF/MVVM 快速开始指南(译)(转)

例 3:命令

绑定到GUI事件是有问题的。WPF给你提供了一个更好的方式,那就是ICommand接口。许多控件都有一个命令属性。这些控件同样服从绑定就像Content和ItemSource,除了你需要绑定它到一个属性上外还要返回一个ICommand接口。对于我们在这里看到的微不足道的例子来说,我们仅仅实现了一个被称为“RelayCommand”很小的类,它实现了ICommand接口:

WPF/MVVM 快速开始指南(译)(转)
 public class RelayCommand:ICommand
{
#region 成员
readonly Func<Boolean> _canExecute;
readonly Action _execute;
#endregion #region 构造函数
public RelayCommand(Action execute)
:this(execute,null)
{ } public RelayCommand(Action execute,Func<Boolean> canExecute)
{
if (execute == null)
{
throw new ArgumentNullException("execute");
}
_execute = execute;
_canExecute = canExecute;
}
#endregion #region ICommand 成员 public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute();
} public event EventHandler CanExecuteChanged; public void Execute(object parameter)
{
_execute();
} #endregion
}
WPF/MVVM 快速开始指南(译)(转)

ICommand接口需要用户定义两个方法:bool CanExecute方法,和void Execute方法。CanExecute方法实际上仅对用户说,我可以执行这个命令吗?这对管理context是很有用的,你可以执行GUI的动作。在我们的例子里,我们不在意这个,所以我们返回true,意味着框架总是可以调用“Execute”方法。你可能会有一种情况,你有一个命令绑定到了按钮上,它只能在你选择了列表里的某一项后才能执行。你可能会在“CanExecute”方法里实现这个逻辑。
由于我们想重复使用ICommand接口的代码,我们使用RelayCommand类,它包含了所有可以重复使用的代码,那些我们不想继续写的代码。
为了展示ICommand是多么容易被复用,我们给一个按钮和一个菜单项都绑定了更新艺术家命令。

WPF/MVVM 快速开始指南(译)(转)
<UserControl  x:Class="Example3.MainWindow" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Example3"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400"> <UserControl.DataContext>
<!--声明创建一个SongViewModel的实例-->
<local:SongViewModel/>
</UserControl.DataContext> <Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button Content="更新艺术家" Grid.Row="0" Grid.ColumnSpan="2" Width="80"
HorizontalAlignment="Left" Command="{Binding UpdateArtistName}"></Button>
<TextBlock Grid.Column="0" Grid.Row="1" Text="例3 - 使用ICommand接口!" />
<TextBlock Grid.Column="0" Grid.Row="2" Text="艺术家: " />
<TextBlock Grid.Column="1" Grid.Row="2" Text="{Binding ArtistName}" />
<Button Grid.Column="1" Grid.Row="3" Name="ButtonUpdateArtist" Content="更新艺术家姓名"
Command="{Binding UpdateArtistName}"/>
</Grid>
</UserControl>
WPF/MVVM 快速开始指南(译)(转)

注意,我们不再绑定按钮指定的Click事件,或者菜单指定的Click事件。

WPF/MVVM 快速开始指南(译)(转)
public partial class MainWindow : UserControl
{
//注意:现在我们没有使用控件指定的事件,我们不需要引用视图模型
public MainWindow()
{
InitializeComponent();
}
}
WPF/MVVM 快速开始指南(译)(转)

点击两个按钮都能工作。

WPF/MVVM 快速开始指南(译)(转)

例4:框架

如果你已经仔细的阅读过这篇文章,到目前为止,你可能注意到有许多重复的代码:注册INPC,或创建命令。这是大多数代码的样板文件,对于INPC来说,我们可以将它移到一个基类里面以方便我们能“ObservableObject”。对于RelayCommand类来说,我们可以移动它到我们的.NET类库里面。你在网上找到的所有MVVM框架(Prism,Calibum等)都是这样开始的。
 就“ObservableObject”和“RelayCommand”类的联系来讲,他们宁愿变得更基本,进行重构是必然的结果。这些类实际上几乎和Josh Smith写的那些类一模一样,这一点也不让人感到吃惊。

所以我们将这些类移动到一个小型类库,以便于我们可以在将来复用。

这结果看起来和以前非常相似:

WPF/MVVM 快速开始指南(译)(转)

例5:歌曲集合,错误的做法

我曾经说过,为了在你的试图(例如xaml)里显示集合里的条目,你需要使用ObservableCollection.在这个例子里,我们创建了一个AlbumViewModel,它非常漂亮的把我们的歌曲收集到了一起在人们能理解的一些事情上.我们也引进一个简单的歌曲数据库,只是为了让我们能在这个例子中快速的产生一些歌曲信息.

你的第一次尝试可能会像下面这样:

WPF/MVVM 快速开始指南(译)(转)
 public class AlbumViewModel
{
#region 成员
ObservableCollection<Song> _songs = new ObservableCollection<Song>();
#endregion
}
WPF/MVVM 快速开始指南(译)(转)

你可能会想:"这时候我有一个不同的试图模型,我想作为一个AlbumViewModel显示这些歌曲,而不是SongViewModel".

我们也创建一些更多的命令然后把他们附加到一些按钮上:

public ICommand AddAlbumArtist {}

public ICommand UpdateAlbumArtists {}

在这个例子中,点击"添加艺术家"会工作得很好,不过点击"更新艺术家名称"将不能工作.如果你读了MSDN这一页黄色高亮的注释,它是这样解释的:

  为了充分的支持数据值从绑定的数据源对象传递到绑定目标,你的集合中的每一个对象,它支持可绑定的属性必须实现一个恰当的属性改变通知机制,例如INotifyPropertyChanged接口.

我们的视图看起来是这样的:

例6:歌曲集合,正确的做法

在最后这个例子中,我们把AlbumViewModel安装到有一个ObservableCollection的SongViewModels上,以便我们更容易的创建它:

现在我们所有的按钮都绑定到命令上来操作我们的集合,我们的后台代码MainWindow.cs仍然是十分的干净.

我们的视图看起来是这样:

结论

实例化你的视图模型

最后值得一提的是,当你在xaml中声明你的视图模型的时候,你不能给它传递任何参数:换句话说,你的视图模型必须有一个
隐式的或者显示的缺省构造函数.在视图模型上添加多少个状态完全取决于你,你也许发现在Mainwindow.cs后台代码里声明视图模型会更容易,在这里你可以传递构造参数.

其他的框架

有许多其他的复杂度和功能不同的MVVM框架,他们以WPF,WinPho7,Silverlight或者这三个的任何组合作为目标.

最后..

希望这6个例子能向你展示出使用MVVM写一个WPF应用程序是多么的简单,我试图覆盖所有的要点,这些要点是我认为很重要的而且经常在许多文章里被讨论.

如果你发现这篇文章有用,请投一票.

如果你在这篇文章中发现了错误,或者我说的有不对的对方,或者你有一些关于这篇文章的其他问题,请在下面留下评论解释为什么,以及你是怎么样适应他的.

引用

写这篇文章的时候我已经遵守了各种.NET编程指南约定和风格.我在编写这篇文章的时候用到的引用列表列在这里:

  1. Effective C#
  2. Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries
  3. C# 4.0 in a Nutshell: The Definitive Reference
  4. WPF 4 Unleashed
  5. Josh Smith

WPF/MVVM 快速开始指南(译)(转)的更多相关文章

  1. &lbrack;转&rsqb;WPF&sol;MVVM快速开始手册

    I will quickly introduce some topics, then show an example that explains or demonstrates each point. ...

  2. WPF&sol;MVVM 快速开发

    http://www.codeproject.com/Articles/165368/WPF-MVVM-Quick-Start-Tutorial 这篇文章醍醐灌顶,入门良药啊! Introductio ...

  3. WPF&sol;MVVM快速指引

    简介 最近微软推出了UWA,又是一波新的C#+xaml学习热.好多小伙伴都对MVVM感觉很好奇,但是有些地方也有点难以理解.特意写了这边文章,希望对你有帮助. 这边文章会很长,所以我会用几个例子的形式 ...

  4. WPF管理系统开发框架搭建指南,2020从入门到放弃

    WPF技术是一个很不错的技术,但一直没有上手过正式的项目,趁在做这个医疗项目时,遂搭建一个WPF开发框架,目的是为了统一WPF开发并提高开发效率:我对WPF技术算是零基础,现学现卖,用这些不成体系的文 ...

  5. WPF MVVM UI分离之《交互与数据分离》 基础才是重中之重~delegate里的Invoke和BeginInvoke 将不确定变为确定系列~目录(&OpenCurlyDoubleQuote;机器最能证明一切”) 爱上MVC3系列~全局异常处理与异常日志 基础才是重中之重~lock和monitor的区别 将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行 将不确定变成确定~LINQ DBML模型可以对

    WPF MVVM UI分离之<交互与数据分离>   在我们使用WPF过程中,不可避免并且超级喜欢使用MVVM框架. 那么,使用MVVM的出发点是视觉与业务逻辑分离,即UI与数据分离 诸如下 ...

  6. WPF MVVM 验证

    WPF MVVM(Caliburn.Micro) 数据验证 书接前文 前文中仅是WPF验证中的一种,我们暂且称之为View端的验证(因为其验证规是写在Xaml文件中的). 还有一种我们称之为Model ...

  7. Rancher 快速上手指南操作&lpar;1&rpar;

    Rancher 快速上手指南操作(1)该指南知道用户如何快速的部署Rancher Server 管理容器.前提是假设你的机器已经安装好docker了.1 确认 docker 的版本,下面是 ubunt ...

  8. AngularJS快速入门指南20:快速参考

    thead>tr>th, table.reference>tbody>tr>th, table.reference>tfoot>tr>th, table ...

  9. AngularJS快速入门指南19:示例代码

    本文给出的大部分示例都可以直接运行,通过点击运行按钮来查看结果,同时支持在线编辑代码. <div ng-app=""> <p>Name: <input ...

随机推荐

  1. js学习之变量、作用域和内存问题

    js学习之变量.作用域和内存问题 标签(空格分隔): javascript 变量 1.基本类型和引用类型: 基本类型值:Undefined, Null, Boolean, Number, String ...

  2. SQL Tuning 基础概述04 - Oracle 表的类型及介绍

    Tables A table describes an entity such as employees. You define a table with a table name, such as ...

  3. linux hosts文件详&plus;mac主机名被莫名其妙修改

    1.名词解析 主机名: 无论是在局域网还是在INTERNET上,每台主机都有一个IP地址,用来区分当前是那一台机器(其实底层是使用机器的物理地址),也就是说IP地址就是一个主机的门牌号,唯一的标示这一 ...

  4. AOP 事务

    定义 AOP实际可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术,非业务类横切于业务类), 通过AOP以动态和非入侵方式来增强服务 事务的四大属性:ACID ...

  5. Canny边缘检测算法的实现

    图像边缘信息主要集中在高频段,通常说图像锐化或检测边缘,实质就是高频滤波.我们知道微分运算是求信号的变化率,具有加强高频分量的作用.在空域运算中来说,对图像的锐化就是计算微分.由于数字图像的离散信号, ...

  6. Jquery字符串,数组(拷贝、删选、合并等),each循环,阻止冒泡,ajax出错,&dollar;&period;grep筛选,&dollar;&period;param序列化,&dollar;&period;when

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  7. mysql 的 alter table 操作性能小提示

    通常情况下,修改表的结构一般不会有太大问题,无非就是一个 alter table 操作,但是对于大表做 alter 操作是一个大问题,请小伙伴们慎重. mysql执行大部分修改表结构操作方法是创建一个 ...

  8. MySQL主从数据同步延时分析

    一.MySQL数据库主从同步延迟                                                              要了解MySQL数据库主从同步延迟原理,我们 ...

  9. inode占用100&percnt;时硬盘无法写入文件故障处理

    故障现象: 分区无法写入文件. 故障分析: 执行df -h命令发现空间占用不到50%,执行df -hi,发现某分区IUse%值为99%,说明innode已经用完,应该是某些目录下存在大量的小文件导致. ...

  10. FinalShell 推荐

    FinalShell是一体化的的服务器,网络管理软件,不仅是ssh客户端,还是功能强大的开发,运维工具,充分满足开发,运维需求. 用户QQ群 342045988 Windows版下载地址:http:/ ...