Coproject - a RIA Caliburn.Micro demo, part 12

In this part, I would like to use RIA Services a little more and then show you how to customize Caliburn.Micro conventions. Remember to visit Coproject Codeplex site for latest news.

Display metadata

If you remember Part 2, RIA Services use metadata to describe what data should be transferred to the client. But that is not all – you can add things like label text or validation. So, open Coproject.Web/Services/CoprojectService.metadata.cs.

Let’s say we want to change labels in ToDoItem detail:
image

So in ToDoItemMetadata, update the following properties:

[Display(Name="Task", Description="Describe the To-do task.")]
public string Content { get; set; }

[Display(Name = "Deadline", Description = "The latest possible date the task must be finished.")]
public Nullable<DateTime> DueDate { get; set; }

[Include]
[Association("FK_ToDoItems_Users", "UserID", "UserID", IsForeignKey = true)]
[Display(Name="Assigned user")]
public User User;

If you run the application now you will see the metadata applied:
image

Note that you could use other named parameters of [Display] to modify auto-generation of DataForms: AutoGenerateField, Order, Groupname. There are other useful parameters – you can check them on MSDN.

Validation metadata

Matadata can be also used for setting validation restrictions. Update the following:

[Display(Name = "Task", Description = "Describe the To-do task.")]
[Required]
[StringLength(40)]
public string Content { get; set; }

[Range(typeof(DateTime), "1.1.2010", "31.12.2019")]
[Display(Name = "Deadline", Description = "The latest possible date the task must be finished.")]
public Nullable<DateTime> DueDate { get; set; }

And now, when you run the application, you can see something like that (note that the Save button is disabled as there are validation errors):
image

You should look into System.ComponentModel.DataAnnotations for other useful attributes. For example if we set this on DueData:

[Editable(false)]

The field will be disabled for editing even in edit mode. That is how you set your domain on the server so that there is as little as possible of specific code concerning your domain in your presentation layer.

Shared code

As you can see, the User field shows only last name of the user and that is not what we want. This a great opportunity to show you how to use shared code between server and client. All you need to do is to call the file you want to be shared as *.shared.cs. So in Coproject.Web project, create a new file Models/User.shared.cs and set its content as follows:

namespace Coproject.Web.Models
{
        public partial class User
        {
                public string FullName
                {
                        get
                        {
                                return string.Format("{0} {1}", this.FirstName, this.LastName);
                        }
                }
        }
}

It is especially important to use this namespace (so that you can extent the partial class created by RIA Services) and to remove using of System.Web (since tis file is copied to the client as-is and there is no reference to this assembly). Now, we can edit ToDoItemView as follows:

<dataForm:DataField PropertyPath="User">
        <TextBlock Text="{Binding User.FullName}" />
</dataForm:DataField>

Note that you can share validators and other logic this way.
image

Filter on Enter

Another thing I would like to tweak a little bit would be to start filtering right when user hits Enter in the filter text box in ToDoListsView. The easiest way you are probably thinking of would be to add this handler to the Filter text box:

cal:Message.Attach="[KeyDown] = [HandleKeyInFilter($eventargs)]"

and then add this to view model:

public IEnumerable<IResult> HandleKeyInFilter(System.Windows.Input.KeyEventArgs eventargs)
{
        if (eventargs.Key == System.Windows.Input.Key.Enter)
        {
                yield return LoadData().ToSequential();
        }

        yield break;
}

Although this approach would work prefectly, it might not be a good idea to make view model dependent on KeyEventArgs. The best approach would be to customize Caliburn.Micro.Parser.CreateTrigger to support other action s than Event (like EnterPressed, or Gesture Key: Enter that is supported by original Caliburn). But I don’t want to change C.M source here. The last solution I can think of would be to create ExtendedTextBox and add EnterKeyDown event to it:

namespace Coproject.Controls
{
        public class ExtendedTextBox : TextBox
        {
                public event EventHandler EnterKeyDown;

                protected override void OnKeyDown(KeyEventArgs e)
                {
                        base.OnKeyDown(e);

                        if (e.Key == Key.Enter)
                        {
                                OnEnterKeyDown();
                        }
                }

                protected void OnEnterKeyDown()
                {
                        var handler = EnterKeyDown;
                        if (handler != null)
                        {
                                handler(this, EventArgs.Empty);
                        }
                }
        }
}

In order to have the default text box style applied to this new control too, we also have to add this to Custom.xaml:

<Style TargetType="local:ExtendedTextBox" BasedOn="{StaticResource DefaultTextBoxStyle}" />

And then we can easily use this new text box in ToDoListsView:

<local:ExtendedTextBox x:Name="Filter" Style="{StaticResource FilterTextBoxStyle}" 
                                                cal:Message.Attach="[EnterKeyDown] = [LoadData]" />

I, personally, like this way more because view and view models don’t have any clue about views implementation.

Customizing Caliburn.Micro conventions

Since we created a new control, we would like to save some configuration about attaching actions to it and use C.M convention instead. So, open AppBootstrapper, add a call to InitializeConvention() into Configure() and implement it as follows:

private void InitializeConventions()
{
        ConventionManager.AddElementConvention<BusyIndicator>(BusyIndicator.IsBusyProperty, "IsBusy", "Loaded");
        ConventionManager.AddElementConvention<ExtendedTextBox>(ExtendedTextBox.TextProperty, "Text", "EnterKeyDown");
}

The first argument configures to what property should be the respective view model property bound to. So if we name a BusyIndicator ‘Busy’, its IsBusy property will be bound to (viewModel).Busy.

The second arguments describes what property of the control should be taken if this control is set as an action parameter. If you remember LoadData(string filter) then this argument is responsible that the Text property of ‘Filter’ text box was passed.

The third argument configures the default event to start actions.

Now, we can update these two controls in ToDoListsView as follows:

<local:ExtendedTextBox x:Name="Filter" Style="{StaticResource FilterTextBoxStyle}" cal:Message.Attach="LoadData" />
<toolkit:BusyIndicator x:Name="Busy_IsBusy"  Grid.RowSpan="2" />

Note: I am not saying that this is exactly what you should do in your projects, it was just a great example for showing how these things work. You have to think about it and decide yourself – concrete decision depends on many factors.

Opened details counter

I found this quite useful when experimenting with details opening and closing so if you want to, add this code to ToDoListsView, above Toolbar:

<StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,-25,0,0">
        <TextBlock Text="Opened details: " Style="{StaticResource StatusTextBlockStyle}" />
        <TextBlock x:Name="Items_Count" Style="{StaticResource StatusTextBlockStyle}" />
</StackPanel>

I think that by now, you are so familiar with the concept that there is no need to describe what this does.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值