【无标题】

WPF MvvMLight

欢迎使用Markdown编辑器在这里插入代码片

一、MVVM概述

MVVM是Model-View-ViewModel的简写,主要目的是为了解耦视图(View)和模型(Model)。

MVVM结构如下:

相对于之前把逻辑结构写在Code Behind 的方式,MVVM模式几乎完全解耦了视图和逻辑业务的关系,通过数据绑定和命令绑定来处理UI属性及事件驱动;
同时,ViewModel中对属性的变更也会通知到View前端,让View前端实时更新。
二、MVVMLight概述
MVVMLight是一个实现MVVM模式的轻量级框架(相对于Prism),能够更好的帮助我们开发WPF 、Windows Phone、Windows 8、SilverLight相关项目。
MVVMLight的作者Laurent Bugnion 是个微软MVP,作者将代码开源到Codeplex上面:http://mvvmlight.codeplex.com/。
MVVMLight的官网:http://www.mvvmlight.net/,上面有详细的介绍和视频文档,有兴趣可以了解下。
MvvMLight包含的动态库:

三、MVVMLight框架初探
通过NuGet安装MVVM Light 框架后,我们新建的Wpf项目中会自动生成一个ViewModel文件夹,里面有MainViewModel.cs和ViewModelLocator.cs两个文件。
下面我们就首先分析下这两个文件的内容:
MainViewModel.cs文件分析:
MainViewModel.cs文件中只有一个类MainViewModel,该类是主窗口MainWindow对应的ViewModel,继承自类ViewModelBase
ViewModelBase类又继承类ObservableObject,同时实现ICleanup接口
ObservableObject类实现INotifyPropertyChanged接口,用于通知属性的改变
由此分析,我们可以得出以下一般结论:
当我们定义一个自己的ViewModel时,一般让自定义ViewModel继承自ViewModelBase类,这样当ViewModel中属性发生变化的时候,就可以自动通知对应的VIew。

ViewModelLocator.cs文件分析:
ViewModelLocator.cs文件中只有一个ViewModelLocator类,类中包括一个构造函数、一个类型为MainViewModel的Main属性、以及一个静态的Cleanup函数。

复制代码
复制代码
public class ViewModelLocator
{
///
/// Initializes a new instance of the ViewModelLocator class.
///
public ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

        if (ViewModelBase.IsInDesignModeStatic)
        {
            // Create design time view services and models
            SimpleIoc.Default.Register<IDataService, DesignDataService>();
        }
        else
        {
            // Create run time view services and models
            SimpleIoc.Default.Register<IDataService, DataService>();
        }

        SimpleIoc.Default.Register<MainViewModel>(); //容器在这里注册了MainViewModel类
    }

    public MainViewModel Main
    {
        get
        {
            return ServiceLocator.Current.GetInstance<MainViewModel>();//容器获取MainViewModel类
        }
    }
    
    public static void Cleanup()
    {
        // TODO Clear the ViewModels
    }
}

复制代码
复制代码
在构造函数中,创建了一个SimpleIoc类型的单实例,用于注册ViewModel,然后用ServiceLocator对这个SimpleIoc类型的单实例进行包裹,方便统一管理。
观察App.xaml文件,我们会发现ViewModelLocator类被生成资源字典并加入到了全局资源,所以每次App初始化的时候,就会去初始化ViewModelLocator类。

实际上,他是一个很基本的视图模型注入器,在构造器中把使用到的ViewModel统一注册,并生成单一实例。然后使用属性把它暴露出来,每当我们访问属性的时候,就会返回相应的ViewModel实例。

复制代码
复制代码

<Application.Resources>

<vm:ViewModelLocator x:Key=“Locator” d:IsDataSource=“True” xmlns:vm=“clr-namespace:MvvmLightDemo.ViewModel” />

</Application.Resources>

复制代码
复制代码
ViewModel文件分析:类继承了ViewModelBase

复制代码
public class MainViewModel : ViewModelBase
{
///
/// Initializes a new instance of the MainViewModel class.
///
public MainViewModel()
{
if (IsInDesignMode)
{
// Code runs in Blend --> create design time data.

            this.MyProperty = "Hello 123![单独]";
        }
        else
        {
            this.MyProperty = "你好 456!";
            // Code runs "for real"
        }
    }

    private string myVar;

    public string MyProperty
    {
        get { return myVar; }
        set { myVar = value; this.RaisePropertyChanged(); } //this.RaisePropertyChanged()触发界面更改
    }

    private int _value;

    public int Value
    {
        get { return _value; }
        set { Set<int>(ref _value, value); }//Set里面已经实现了RaisePropertyChanged
    }


}

复制代码
四、MVVMLight命令RelayCommand

在MVVM Light框架中,主要通过命令绑定来进行事件的处理。

WPF中,命令是通过实现 ICommand 接口创建的。 ICommand 公开了两个方法(Execute 及 CanExecute)和一个事件(CanExecuteChanged)。

在MVVM Light框架中,RelayCommand类实现了ICommand 接口,用于完成命令绑定。

通过RelayCommand类的构造函数传入Action类型的Execute委托和Func类型的CanExecute委托,CanExecute委托用于表示当前命令是否可以执行,Execute委托则表示执行当前命令对应的方法。

通过命令绑定,解耦了View和ViewModel的行为交互,将视图的显示和业务逻辑分开。比如我们对界面上的某个按钮进行命令绑定,当点击按钮的时候,实际上进行操作是在对应的ViewModel下的所绑定的方法中执行的。

RelayCommand包含带参数跟不带参数的,带参数的就用泛型RelayCommand对象

1、带一个参数的命令绑定

代码片段如下:

复制代码
复制代码





    public RelayCommand<string> AddUserCommand
    {
        get
        {
            if (addUserCommand == null)
            {
                addUserCommand = new RelayCommand<string>(AddUser, (string p) => { return IsCanAddUser; });
            }
            return addUserCommand;
        }
        set { addUserCommand = value; }
    }
    private void AddUser(string par)
    {
        UserList = UserList + "  " + par;
    }

复制代码
复制代码
2、带多个参数的命令绑定

给命令传递多个参数,建议使用以下方式:

使用MultiBinding将多绑定的各个值转换成我们所需的对象或者实例模型,再传递给ViewModel中的命令。

代码片段如下:

复制代码
复制代码

<Window.Resources>
<cvt:UserInfoConverter x:Key=“userInfoConverter”></cvt:UserInfoConverter>
</Window.Resources>
<Window.DataContext>

</Window.DataContext>






    <StackPanel>
        <GroupBox Header="带对象类型参数的命令" BorderBrush="#FF11519C" BorderThickness="1" FontSize="16" Foreground="#FF127C0D" Margin="2">
            <StackPanel>
                <StackPanel Orientation="Horizontal">
                    <Label Content="UserName:" FontSize="16" ></Label>
                    <TextBox Width="200" Name="tbxUser" FontSize="16" />
                    <Label Content="Password:" FontSize="16" ></Label>
                    <TextBox Width="200" Name="tbxPwd" FontSize="16" />
                    <Button Content="AddUser" Command="{Binding AddUserCommandWithObjPar}">
                        <Button.CommandParameter>
                            <MultiBinding Converter="{StaticResource userInfoConverter}">
                                <Binding ElementName="tbxUser" Path="Text"/>
                                <Binding ElementName="tbxPwd" Path="Text"/>
                            </MultiBinding>
                        </Button.CommandParameter>
                        
                    </Button>
                </StackPanel>
                <StackPanel Orientation="Horizontal">
                    <Label Content="Parameter:"  FontSize="16" ></Label>
                    <Label Content="{Binding ObjParameter}"  FontSize="16" ></Label>

                </StackPanel>
            </StackPanel>
        </GroupBox>
    </StackPanel>

    <StackPanel>
        <GroupBox Header="事件转命令" BorderBrush="#FF11519C" BorderThickness="1" FontSize="16" Foreground="#FFCDAA0C" Margin="2">
            <StackPanel>
                <StackPanel>
                    <ListBox x:Name="lb" ItemsSource="{Binding ListBoxData}"  BorderThickness="0" SelectedIndex="{Binding SelectIndex}" >
                        <i:Interaction.Triggers>
                            <i:EventTrigger EventName="SelectionChanged">
                                <mvvm:EventToCommand Command="{Binding SelectionChangedCommand}"/>
                            </i:EventTrigger>
                        </i:Interaction.Triggers>
                        <ListBox.ItemsPanel>
                            <ItemsPanelTemplate>
                                <WrapPanel Width="{Binding ActualWidth,RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}"/>
                            </ItemsPanelTemplate>
                        </ListBox.ItemsPanel>

                        <ListBox.ItemTemplate>
                            <DataTemplate>
                                <Border BorderBrush="AntiqueWhite" BorderThickness="1">
                                    <StackPanel Margin="2">

                                        <Image Source="{Binding Img}" Width="96" Height="96"/>
                                        <TextBlock HorizontalAlignment="Center" Text="{Binding Info}"/>
                            
                                   
                                </StackPanel>
                                </Border>
                            </DataTemplate>
                        </ListBox.ItemTemplate>
                    </ListBox>
                    <Label Content="您选择的是:" FontSize="16" ></Label>
                    <Label Content="{Binding Path=SelResult,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" FontSize="16" />
                </StackPanel>
            </StackPanel>
        </GroupBox>
    </StackPanel>

</StackPanel>
复制代码 复制代码 复制代码 复制代码 using MvvmLightDemo1.ViewModel; using System; using System.Linq; using System.Windows.Data;

namespace MvvmLightDemo1.Converter
{
public class UserInfoConverter: IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (!values.Cast().Any(text => string.IsNullOrEmpty(text)) && values.Count() == 2)
{
UserModel userModel = new UserModel() { UserName = values[0].ToString(), PassWord = values1.ToString()};
return userModel;
}

        return null;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

}
复制代码
复制代码
复制代码
复制代码
private RelayCommand addUserCommandWithObjPar;

    public RelayCommand<UserModel> AddUserCommandWithObjPar
    {
        get
        {
            if (addUserCommandWithObjPar == null)
            {
                addUserCommandWithObjPar = new RelayCommand<UserModel>(AddUserWithObjPar);
            }
            return addUserCommandWithObjPar;
        }
        set { addUserCommandWithObjPar = value; }
    }
    private void AddUserWithObjPar(UserModel par)
    {
        ObjParameter = "UserName: "+ par.UserName + " Password: " + par.PassWord;
    }

复制代码
复制代码
3、EventToCommand
在WPF中,并不是所有控件都有Command,例如TextBox,那么当文本改变,我们需要处理一些逻辑,这些逻辑在ViewModel中,没有Command如何绑定呢?

这个时候我们就用到EventToCommand,事件转命令,可以将一些事件例如TextChanged,Checked等事件转换成命令的方式。

接下来我们就以ListBox为例子,来看看具体的实例:

View代码:(这边声明了i特性和mvvm特性,一个是为了拥有触发器和行为附加属性的能力,当事件触发时,会去调用相应的命令,EventName代表触发的事件名称;一个是为了使用MVVMLight中 EventToCommand功能。)

这边就是当ListBox执行SelectionChanged事件的时候,会相应去执行ViewModel中 SelectionChangedCommand命令。

代码片段如下:

复制代码

<Window.Resources>
<cvt:UserInfoConverter x:Key=“userInfoConverter”></cvt:UserInfoConverter>
</Window.Resources>
<Window.DataContext>

</Window.DataContext>






    <StackPanel>
        <GroupBox Header="带对象类型参数的命令" BorderBrush="#FF11519C" BorderThickness="1" FontSize="16" Foreground="#FF127C0D" Margin="2">
            <StackPanel>
                <StackPanel Orientation="Horizontal">
                    <Label Content="UserName:" FontSize="16" ></Label>
                    <TextBox Width="200" Name="tbxUser" FontSize="16" />
                    <Label Content="Password:" FontSize="16" ></Label>
                    <TextBox Width="200" Name="tbxPwd" FontSize="16" />
                    <Button Content="AddUser" Command="{Binding AddUserCommandWithObjPar}">
                        <Button.CommandParameter>
                            <MultiBinding Converter="{StaticResource userInfoConverter}">
                                <Binding ElementName="tbxUser" Path="Text"/>
                                <Binding ElementName="tbxPwd" Path="Text"/>
                            </MultiBinding>
                        </Button.CommandParameter>
                        
                    </Button>
                </StackPanel>
                <StackPanel Orientation="Horizontal">
                    <Label Content="Parameter:"  FontSize="16" ></Label>
                    <Label Content="{Binding ObjParameter}"  FontSize="16" ></Label>

                </StackPanel>
            </StackPanel>
        </GroupBox>
    </StackPanel>

    <StackPanel>
        <GroupBox Header="事件转命令" BorderBrush="#FF11519C" BorderThickness="1" FontSize="16" Foreground="#FFCDAA0C" Margin="2">
            <StackPanel>
                <StackPanel>
                    <ListBox x:Name="lb" ItemsSource="{Binding ListBoxData}"  BorderThickness="0" SelectedIndex="{Binding SelectIndex}" >
                        <i:Interaction.Triggers>
                            <i:EventTrigger EventName="SelectionChanged">
                                <mvvm:EventToCommand Command="{Binding SelectionChangedCommand}"/>
                            </i:EventTrigger>
                        </i:Interaction.Triggers>
                        <ListBox.ItemsPanel>
                            <ItemsPanelTemplate>
                                <WrapPanel Width="{Binding ActualWidth,RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}"/>
                            </ItemsPanelTemplate>
                        </ListBox.ItemsPanel>

                        <ListBox.ItemTemplate>
                            <DataTemplate>
                                <Border BorderBrush="AntiqueWhite" BorderThickness="1">
                                    <StackPanel Margin="2">

                                        <Image Source="{Binding Img}" Width="96" Height="96"/>
                                        <TextBlock HorizontalAlignment="Center" Text="{Binding Info}"/>
                            
                                   
                                </StackPanel>
                                </Border>
                            </DataTemplate>
                        </ListBox.ItemTemplate>
                    </ListBox>
                    <Label Content="您选择的是:" FontSize="16" ></Label>
                    <Label Content="{Binding Path=SelResult,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" FontSize="16" />
                </StackPanel>
            </StackPanel>
        </GroupBox>
    </StackPanel>
 <StackPanel>
        <GroupBox Header="带事件本身参数的命令" BorderBrush="#FF11519C" BorderThickness="1" FontSize="16" Foreground="#FF127C0D" Margin="2">

            <StackPanel Orientation="Horizontal">
                <Button Content="拖拽上传文件" AllowDrop="True">
                    <i:Interaction.Triggers>
                    <i:EventTrigger EventName="Drop">
                        <mvvm:EventToCommand PassEventArgsToCommand="True" Command="{Binding DropCommand}" />
                    </i:EventTrigger>
                    </i:Interaction.Triggers>
                </Button>
                <Label Content="FilePath:"  FontSize="16" ></Label>
                <Label Content="{Binding DraggedFilePath}"  FontSize="16" ></Label>

            </StackPanel>

        </GroupBox>
    </StackPanel>


复制代码
五、MVVMLight消息Messenger

Messeger是信使的意思,顾名思义,他的目是用于View和ViewModel 以及 ViewModel和ViewModel 之间的消息通知和接收。Messenger类用于应用程序的通信,接受者只能接受注册的消息类型,另外目标类型可以被指定,用Send<TMessage, TTarget>(TMessage message)实现,在这种情况下信息只能被传递如果接受者类型和目标参数类型匹配,message可以是任何简单或者复杂的对象,你可以用特定的消息类型或者创建你自己的类型继承自他们。

Messenger首先需要注册一下,用来接收消息

Messenger.Default.Register(this, (o) =>
{
MessageBox.Show(“收到字符串数据:” + o);
});

Messenger.Default.Register(this, (o) =>
{
MessageBox.Show(“收到字符串数据:” + o);
},“token”);//带令牌的注册

// 接口注册receiveDerivedMessagesToo为false,继承的对象发送将不能接收,为TRUE继承的对象发送可以接收
Messenger.Default.Register(this, false, (o) =>
{

});

比如Messanger.Default.Send()//false,发送不能接收

Messanger.Default.Register泛型方法,T代表指定类型,只有发送这个类型的消息才能被指定泛型注册的方法捕获到

消息发送:

Messenger.Default.Send(“123”);
Messenger.Default.Send(“123”, “token”);//"token"消息令牌,如果带了令牌,只有注册了该令牌的消息才能接收到

Messenger.Default.Send(new NotificationMessage(this, “123”));

Messenger.Default.Send(null, “token”);//如果需要发送广播消息,消息内容为空

Message消息对象类型 说明

MessageBase 简单的消息类,携带可选的信息关于消息发布者的

GenericMessage 泛型消息

NotificationMessage 用于发送一个string类型通知给接受者
NotificationMessage
和上面一样是一个,且具有泛型功能

NotificationMessage 向接受者发送一个通知,允许接受者向发送者回传消息
NotificationMessageAction NotificationMessage的泛型方式
DialogMessage 发送者(通常是View)显示对话,并且传递调用者得回传结果(用于回调),接受者可以选择怎样显示对话框,可以使是标准的MessageBox也可也是自定义弹出窗口
PropertyChangedMessage 用于广播一个属性的改变在发送者里,和PropertyChanged事件有完全箱体内各的目的,但是是一种弱联系方式

DialogMessage发送代码:

//通过命令发送令牌信息
public ICommand TestMathCommand
{
get
{
return new RelayCommand(() =>
{
DialogMessage msg = new DialogMessage(“提示正文”, MessageBoxCallBack);
//设置弹出的MessageBox的类型,包含两个按钮,一个"确认", 一个"取消"
msg.Button = MessageBoxButton.OKCancel;
msg.Caption = “标题”;
Messenger.Default.Send(msg);
});
}
}

private void MessageBoxCallBack(MessageBoxResult ret)
{
if (ret == MessageBoxResult.OK)
{
MessageBox.Show(“弹窗点击了确认。继续执行。”);
}
}
DialogMessage接收代码:

public MainWindow()
{
InitializeComponent();
Messenger.Default.Register(this, dlgmsg =>
{
var res = MessageBox.Show(dlgmsg.Content, dlgmsg.Caption, dlgmsg.Button);
dlgmsg.Callback(res); //这句会此起ViewModel中的MessageBoxCallBack调用
});
}
DialogMessage包含了弹出框需要的全部信息,包括标题,正文和回调函数。在这个Demo中需要注意一下MessageBox是模态的,因此当执行到MessageBox.Show()时,执行流会卡住,等到用户点击"OK"惑"Cancel"按钮后,程序才会继续执行。

NotificationMessageAction发送代码:

//通过命令发送令牌信息
public ICommand TestMathCommand
{
get
{
return new RelayCommand(() =>
{
NotificationMessageAction msg = new NotificationMessageAction(“主页面测试”, (ret) =>
{
if (ret == MessageBoxResult.OK)
{
MessageBox.Show(“弹窗点击了确认。继续执行。”);
}
}
);

Messenger.Default.Send<NotificationMessageAction>(msg);
});
}
}
NotificationMessageAction接收代码:

public MainWindow()
{
InitializeComponent();
Messenger.Default.Register<NotificationMessageAction>(this, (msg) =>
{
var ret = MessageBox.Show(“内容”, “标题”, MessageBoxButton.OKCancel);
//msg.Notification内容是“主页面测试”
if (msg.Notification != null)
{
msg.Execute(ret);
}
}
);
}
如果ViewModel需要向View发送一个对象,可以使用 NotificationMessage<类型>的泛型版本

// PropertyChangedMessage属性消息,当属性更改会触发消息通知,属性需要把广播的参数设置为true

比如:public string name

{

get

{

return _name;

}

set

{

set(ref _name,value,broadcast:true);

}

}
Messenger.Default.Register<PropertyChangedMessage>(this, (o) =>
{
if (o.PropertyName == “MyProperty”)// 区别一下哪个属性进行了变化
{

}
});

六、MVVMLight DispatchHelper UI更新

在应用程序中,线程可以被看做是应用程序的一个较小的执行单位。每个应用程序都至少拥有一个线程,我们称为主线程。当调用和操作主线程的时候,该操作将动作添加到一个队列中,每个操作均按照将它们添加到队列中的顺序连续执行,但是可以通过为这些动作指定优先级来影响执行顺序,而负责管理此队列的对象称之为线程调度程序。

我们知道,WPF程序中,控件是属于UI线程的,如果试图在子线程中访问或者更新UI,就需要在子线程中通知主线程来处理UI, 通过向主线程的Dispatcher队列注册工作项,来通知UI线程更新结果。

Dispatcher提供两个注册工作项的方法:Invoke 和 BeginInvoke。

这两个方法均调度一个委托来执行。Invoke 是同步调用,也就是说,直到 UI 线程实际执行完该委托它才返回。BeginInvoke是异步的,将立即返回。

代码片段如下:

this.Dispatcher.BeginInvoke((Action)delegate()
{
更新UI控件ing;
});
通常情况下,ViewModel 不从 DispatcherObject 继承,不能访问 Dispatcher 属性。这时候,我们需要使用DispatcherHelper 组件来更新UI。

实际上,该类所做的是将主线程的调度程序保存在静态属性中,并公开一些实用的方法,以便通过统一的方式访问。

为了实现正常功能,需要在主线程上初始化该类。

通常,在 MVVM Light 应用程序中,DispatcherHelper 可以在 App.xaml.cs 或者ViewModel的构造函数中进行初始化,App.xaml.cs 是定义应用程序启动类的文件。

在 WPF 中,该类一般是在 App 构造函数中进行初始化的。

DispatcherHelper组件初始化以后,DispatcherHelper 类的 UIDispatcher 属性包含对主线程的调度程序的引用。

但是一般很少直接使用该属性,虽然确实可以使用。通常我们会使用 CheckBeginInvokeOnUi 方法来更新UI。

七、MVVMLight 消息对话框

首先实现IDialgService类,然后注册类,然后调用类显示消息对话框

注册对话框类:

复制代码
public class B : IA, IDialogService
{
public B()
{
}

    public void Show()
    {
        throw new NotImplementedException();
    }

    public Task ShowError(string message, string title, string buttonText, Action afterHideCallback)
    {
        throw new NotImplementedException();
    }

    public Task ShowError(Exception error, string title, string buttonText, Action afterHideCallback)
    {
        throw new NotImplementedException();
    }

    public Task ShowMessage(string message, string title)
    {
        MessageBox.Show(message, title);
        return null;
    }

    public Task ShowMessage(string message, string title, string buttonText, Action afterHideCallback)
    {
        throw new NotImplementedException();
    }

    public Task<bool> ShowMessage(string message, string title, string buttonConfirmText, string buttonCancelText, Action<bool> afterHideCallback)
    {
        throw new NotImplementedException();
    }

    public Task ShowMessageBox(string message, string title)
    {
        throw new NotImplementedException();
    }
}

复制代码
注册类

// IDialogService的使用
SimpleIoc.Default.GetInstance().ShowMessage(“”, “”);

新的改变

我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:

  1. 全新的界面设计 ,将会带来全新的写作体验;
  2. 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示;
  3. 增加了 图片拖拽 功能,你可以将本地的图片直接拖拽到编辑区域直接展示;
  4. 全新的 KaTeX数学公式 语法;
  5. 增加了支持甘特图的mermaid语法1 功能;
  6. 增加了 多屏幕编辑 Markdown文章功能;
  7. 增加了 焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置 等功能,功能按钮位于编辑区域与预览区域中间;
  8. 增加了 检查列表 功能。

功能快捷键

撤销:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜体:Ctrl/Command + I
标题:Ctrl/Command + Shift + H
无序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
检查列表:Ctrl/Command + Shift + C
插入代码:Ctrl/Command + Shift + K
插入链接:Ctrl/Command + Shift + L
插入图片:Ctrl/Command + Shift + G
查找:Ctrl/Command + F
替换:Ctrl/Command + G

合理的创建标题,有助于目录的生成

直接输入1次#,并按下space后,将生成1级标题。
输入2次#,并按下space后,将生成2级标题。
以此类推,我们支持6级标题。有助于使用TOC语法后生成一个完美的目录。

如何改变文本的样式

强调文本 强调文本

加粗文本 加粗文本

标记文本

删除文本

引用文本

H2O is是液体。

210 运算结果是 1024.

插入链接与图片

链接: link.

图片: Alt

带尺寸的图片: Alt

居中的图片: Alt

居中并且带尺寸的图片: Alt

当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。

如何插入一段漂亮的代码片

博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片.

// An highlighted block
var foo = 'bar';

生成一个适合你的列表

  • 项目
    • 项目
      • 项目
  1. 项目1
  2. 项目2
  3. 项目3
  • 计划任务
  • 完成任务

创建一个表格

一个简单的表格是这么创建的:

项目Value
电脑$1600
手机$12
导管$1

设定内容居中、居左、居右

使用:---------:居中
使用:----------居左
使用----------:居右

第一列第二列第三列
第一列文本居中第二列文本居右第三列文本居左

SmartyPants

SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:

TYPEASCIIHTML
Single backticks'Isn't this fun?'‘Isn’t this fun?’
Quotes"Isn't this fun?"“Isn’t this fun?”
Dashes-- is en-dash, --- is em-dash– is en-dash, — is em-dash

创建一个自定义列表

Markdown
Text-to- HTML conversion tool
Authors
John
Luke

如何创建一个注脚

一个具有注脚的文本。2

注释也是必不可少的

Markdown将文本转换为 HTML

KaTeX数学公式

您可以使用渲染LaTeX数学表达式 KaTeX:

Gamma公式展示 Γ ( n ) = ( n − 1 ) ! ∀ n ∈ N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N Γ(n)=(n1)!nN 是通过欧拉积分

Γ ( z ) = ∫ 0 ∞ t z − 1 e − t d t   . \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,. Γ(z)=0tz1etdt.

你可以找到更多关于的信息 LaTeX 数学表达式here.

新的甘特图功能,丰富你的文章

2014-01-07 2014-01-09 2014-01-11 2014-01-13 2014-01-15 2014-01-17 2014-01-19 2014-01-21 已完成 进行中 计划一 计划二 现有任务 Adding GANTT diagram functionality to mermaid
  • 关于 甘特图 语法,参考 这儿,

UML 图表

可以使用UML图表进行渲染。 Mermaid. 例如下面产生的一个序列图:

张三 李四 王五 你好!李四, 最近怎么样? 你最近怎么样,王五? 我很好,谢谢! 我很好,谢谢! 李四想了很长时间, 文字太长了 不适合放在一行. 打量着王五... 很好... 王五, 你怎么样? 张三 李四 王五

这将产生一个流程图。:

链接
长方形
圆角长方形
菱形
  • 关于 Mermaid 语法,参考 这儿,

FLowchart流程图

我们依旧会支持flowchart的流程图:

Created with Raphaël 2.3.0 开始 我的操作 确认? 结束 yes no
  • 关于 Flowchart流程图 语法,参考 这儿.

导出与导入

导出

如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。

导入

如果你想加载一篇你写过的.md文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。


  1. mermaid语法说明 ↩︎

  2. 注脚的解释 ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值