一节我们实现了分类树的右键菜单弹出,本节我们继续实现数据从浏览器到数据库的工作。
我们先来丰富右键菜单的选项,在Menu控件中添加MenuItem,分别是修改节点和删除节点:
<Menu Style="@menuStyle">
<MenuItem OnClick="CreateNode">
@menu_create_text
</MenuItem>
<MenuItem OnClick="ModifyNode">
修改节点
</MenuItem>
<MenuItem OnClick="DeleteNode">
删除节点
</MenuItem>
</Menu>
由于修改和删除不像创建涉及到不同的名称,所以菜单文章内容直接写死。事件响应代码一并复制就好。
void ModifyNode(MouseEventArgs args)
{
menuStyle = "display:none;";
}
void DeleteNode(MouseEventArgs args)
{
menuStyle = "display:none;";
}
运行效果:
我们的右键菜单现在有了事件触发,接下来要弹出分类编辑页面来录入信息。我们首先需要创建一个名为CategoryEdit.Razor组件,过程跟上一节我们创建ContextMenuPanel一样。如下图:
这个过程我们以后就不再讲了。
有同学私信问不使用Ant Design组件,直接用Blazor系统的组件可行吗?我觉得这个问题比较有代表性,所以这个CategoryEdit我就不使用Ant Design的组件来完成。先上完整的代码吧:
<div style="width:100%; display:@display;">
<div class="page">
<div @onclick="toggle" id="close">X</div>
<div style="padding: 10px;">
<ul>
<li class="item"><span>编码:</span><input @bind="@Value.Id" /></li>
<li class="item"><span>名称:</span><input @bind="@Value.Name" /></li>
<li class="item"><span>所属Id:</span><input @bind="@Value.ParentId" /></li>
</ul>
<ul>
<li class="item">
<span>是否有子类:</span>
<select @bind="@has_child">
<option value="1">true</option>
<option value="0">false</option>
</select>
</li>
<li class="item"><span>分类类型:</span><input @bind="@Value.Type" /></li>
<li class="item"><span>显示顺序:</span><input @bind="@Value.ShowOrder" /></li>
</ul>
<div>
<label>分类描述:</label>
<textarea style="width:100%; min-height:200px;" @bind=@Value.Description></textarea>
<label>备注:</label>
<textarea style="width:100%; min-height:200px;" @bind=@Value.Remark></textarea>
</div>
<button @onclick="save">保存</button>
</div>
</div>
</div>
@code {
string display = "none";
public void toggle()
{
display = (display == "none") ? "block" : "none";
}
[Parameter]
public EventCallback OnSave { get; set; }
[Parameter]
public Model.Category Value { get; set; }
int has_child = 0;
void save()
{
Value.HasChild = (has_child == 0) ? false : true;
if (OnSave.HasDelegate) OnSave.InvokeAsync();
}
}
样式文件CategoryEdit.razor.css
.page { width:960px; border: 1px solid #CCC; margin-left:auto; margin-right:auto; }
.item { width: 280px; list-style:none; display: inline-block; }
.item span { width: 100px; display: inline-block; }
#close {
position: relative;
text-align: center;
cursor: pointer;
background: #FCC;
float: right;
width: 20px;
height: 20px;
}
#close:hover {
background-color: #F00;
}
上部分为html元素标签,具体标签和布局就不展开讲了。
@display是引用下面code中的变量,只要display的值变化,这里就会随之生效;
@onclick是绑定click事件;用到了两处,一个是右上角的关闭按钮,一个是下方的保存按钮;
@bind="@Value.Id跟上面的@display类似,只是这个用于控件,控件的值与变量值双向绑定;
public void toggle()是切换是否显示的方法,默认隐藏,调用一次就切换一次;
[Parameter]是定义CategoryEdit组件的属性;
public EventCallback OnSave是声明一个OnSave的函数作为回调;
public Model.Category Value是要编辑或新建的Category数据实体;
int has_child是对应Model.Category中的HasChild,在标准select及option中无法直接绑定bool类型的熟知,所以用has_child来作为媒介;
void save()则是保存函数,做数据处理后回调OnSave;
css文件在blazor中是隔离的,即声明一个跟razor组件同名的css文件,它就会从属于这个razor组件,只对这个razor生效,这样可以很好的解决不同css文件命名相互冲突的问题。
上面完全都是靠代码堆的,这里有点没想明白为什么微软不延续winform、webform的所见即所得的方式,哪怕是有个设计视图浏览也好。难道是技术上过于复杂吗?目前以Blazor这种开发方式,想要看到修改效果,哪怕是只调一个颜色,都只能重新编译运行才能看到效果,非常影响开发效率。以前webform的那种,改前端根本需要编译,重新刷新页面就好。希望这里未来能有改进。
CategoryEdit组件设计完成后,我们就可以在Index.razor中使用它了
<CategoryEdit @ref="categoryEditor" Value="@curCategory" OnSave="@SaveCategory"></CategoryEdit>
@code {
CategoryEdit categoryEditor;
Model.Category curCategory = new Model.Category();
void SaveCategory()
{
}
}
我们只需要这几行代码就够了。对属性赋值,响应事件。然后我们先来看下效果:
我们可以看到,调用完成后,在Index.razor中的SaveCategory函数中,curCategory中的值就都有了。实际上我们用的控件库,比如Ant Design也都是这样一步一步来完成的,只要有时间、有耐心,啥都不是事。
到目前为止,我们已经完成了前端的数据准备,接下来我们就是要通过WebAPI正式向服务器提交信息了。在一般的公司中,前端和后端都是分开不同团队来做的,后端做完提供接口,前端按照接口规范进行调用。那我们接下来的事情就是要做后端的工作了,考虑到同样编码内容较多,这节暂时到这里,我们下节继续。
----------------------------------------------------
本教程项目源码已作为开源项目加入到Gitee,代码内容会随教程实时更新,大家有兴趣的话可以关注我,以获得最及时的更新。私信:
私人日记 可以获取相关链接;
大家阅读过程中有哪些看不懂或未尽兴的地方,可以在评论区留言,我会先记下来在后续的教程中找机会再说。
教程有帮助的话请大家帮忙关注、转发、扩散,能不能开专栏还需要你们的支持!
目中使用到了 updatePanel 和jquery-easyui 。
使用updatepanel的好处自然是页面不刷新,用户感觉比较好,同时也减少了一部分数据量的传输。
使用easyui 的好处除了界面还不错之外,也因为使用方便。
<div class="easyui-tabs" style="width: 300px"> <div title="搜索"> ...</div> <div title="选择">...</div> <div title="返回">...</div></div>只要给他定义个相应的class 就能实现各种效果。
但是,把它放在updatepanel里面,且不是首次就让他显示出来的话就出故障了。
例如:
代码<asp:MultiView ID="MultiView1" runat="server"> <asp:View ID="View1" runat="server"> <div class="easyui-tabs" style="width: 300px"> <div title="搜索"> ...</div> <div title="选择"> ...</div> <div title="返回"> ...</div> </div> </asp:View> <asp:View ID="View2" runat="server"> <div class="easyui-tabs" style="width: 300px"> <div title="搜索"> ...</div> <div title="选择"> ...</div> <div title="返回"> ...</div> </div> </asp:View> </asp:MultiView>在multipleView里面定义两个一样的view,内容也一样。并把 MultiView1放到updatepanel里面。
然后设置他显示第一个view
MultiView1.ActiveViewIndex =0;浏览一下。显示正常。但是当我们改变view的显示时,例如把上面的改成 MultiView1.ActiveViewIndex =1;那么第二个veiw的效果就全无了。
到jquery.easyui.min.js 里找原因。看到了这么一句
r=$(".easyui-tabs",_1ec);if(r.length){r.tabs();大概就是在网页加载完后,寻找class定义为easyui-tabs 的层。并把效果附加给他。
那么可以想象,当页面加载时,我们显示的是第一个view,那么js就找到view里的层,并赋予其效果。
然后我们在updatepanel里更新了显示的view,内容虽然切换到了第二个view了。但是页面没有重新加载,上面的js代码没有对新的view执行改变。
所以决策就是当updatepanel回发后重新执行js代码。
在页面定义一个重新绑定的函数。
function EndRequestHandler() { $(".easyui-tabs").tabs(); }再定义一个事件。 function reload() { Sys.WebForms.PageRequestManager.getInstance().add_endRequest(EndRequestHandler); }add_endRequestPageRequestManager 类是一个管理浏览器中服务器 UpdatePanel 控件的部分页更新。此外,还定义一些属性、事件和方法,用以通过客户端脚本对网页进行自定义。通过调用 getInstance 方法来得到 PageRequestManager 类的实例。然后通过 add_endRequest 方法来绑定 endRequest 事件(异步回发完成,并且控制权返回到浏览器之后引发)。这样以后,每次updatepanel发生回调后,都会触发EndRequestHandler()函数。重新绑定一次效果。$(document).ready(function() { reload(); })失效问题就解决了。
原文:http://www.cnblogs.com/topdog/archive/2010/04/11/1709413.html
上文---磁性窗体的设计01-C#学习进阶
在多媒体播放软件中,经常会遇到一种情况,即当拖动其中一个窗体(主窗体)时,其他的窗体(子窗体)也可以随着该窗体移动,当拖动子窗体时,其他窗体将不跟随移动。这就是磁性窗体。本实例将制作一个磁性窗体,当拖动主窗体移动时,两个子窗体如果相连,则跟随移动。
(1)新建一个Windows应用程序,将其命名为“磁性窗体的设计”,创建3个窗体,分别命名为Frm_Play、Frm_ListBox和Frm_Libretto,将这3个窗体的FormBorderStyle属性设置为None。
(2)在Frm_Play窗体中添加两个Panel控件,分别命名为panel_Title和panel_Close,并将panel_Title控件的Dock属性设置为Top。
说明:Frm_ListBox和Frm_Libretto窗体中所用到控件及其设置与Frm_Play窗体相同,在这里不作详解。
(3)主要程序代码。
磁性窗体的设置实际上就是将相关联的窗体位置和大小记录在公共类FrmClass中,然后在移动窗体时,通过已记录的窗体信息,实现窗体的磁性效果。
下面以Frm_Play窗体为例,介绍磁性窗体的实现过程。
在Frm_Play窗体标题栏上按下鼠标时,获取其他两个窗体的相关信息(这两个窗体与该窗体具有磁性效果)。代码如下:
private void panel_Title_MouseDown(object sender, MouseEventArgs e)
{
int Tem_Y = 0;
if (e.Button == MouseButtons.Left) //按下的是否为鼠标左键
{
Cla_FrmClass.FrmBackCheck();//检测各窗体是否连在一起
Tem_Y = e.Y;
FrmClass.FrmPoint = new Point(e.X, Tem_Y); //获取鼠标在窗体上的位置,用于磁性窗体
FrmClass.CPoint = new Point(-e.X, -Tem_Y); //获取鼠标在屏幕上的位置,用于窗体的移动
if (FrmClass.Example_List_AdhereTo) //如果与frm_ListBox窗体相连接
{
Cla_FrmClass.FrmDistanceJob(this, FrmClass.F_List); //计算窗体的距离差
if (FrmClass.Example_Assistant_AdhereTo) //两个辅窗体是否连接在一起
{
Cla_FrmClass.FrmDistanceJob(this, FrmClass.F_Libretto); //计算窗体的距离差
}
}
if (FrmClass.Example_Libretto_AdhereTo) //如果与frm_ Libretto窗体相连接
{
Cla_FrmClass.FrmDistanceJob(this, FrmClass.F_Libretto); //计算窗体的距离差
if (FrmClass.Example_Assistant_AdhereTo) //两个辅窗体是否连接在一起
{
Cla_FrmClass.FrmDistanceJob(this, FrmClass.F_List); //计算窗体的距离差
}
}
}
}
未完待续。。。。
*请认真填写需求信息,我们会在24小时内与您取得联系。