Commands in Task-It - Part 2

Monday, April 19, 2010 by Ross Wozniak | Comments 18

Download Source Code

Task-It Series

This post is part of a series of blog posts and videos about the Task-It (task management) application that I have been building with Silverlight 4 and Telerik's RadControls for Silverlight 4. For a full index of these resources, please go here. One of the posts listed in the index provides a full source download for the application.

Taking it to the next level

In my last post, Commands in Task-It - Part 1, we looked at a very simple solution that demonstrated how a single command instance (SaveCommand) could be bound to two UI controls, a Button and a RadTreeViewItem. In this example we'll get more complex, binding a single command instance (MoveToCommand) will be bound to multiple RadMenuItems in a RadContextMenu that is tied to a RadGridView. This time we'll also set a separate CommandParameter on each RadMenuItem, so when the command is invoked, we will be able to use that parameter to determine what to do next.

The user interface

This screen shot shows the UI that we will be working with, it is a stripped-down version of Task-It. On the left hand side we have a RadTreeView that lists some task categories and when one is selected the RadGridView on the right displays the tasks for that category. When the user right-clicks on one of the items in the RadGridView a RadContextMenu appears that allows us to move the task to a different category. We're slowly getting closer to the actual Task-It user interface.

Sorry that the image gets a bit mangled by sizing it down!

RadContextMenuItem Commands

How it works

When the app first loads up there are no categories selected on the left, so a message displays on the right stating "Please select a category.". If you select a category that has at least one task in it (the Inbox and Actions categories currently do) the RadGridView will display the tasks in that category. If you select a category that does not have tasks, a message displays stating that "The selected category has no tasks.".

The code

First let's look at the one 'view' involved in the UI. When MainPage.xaml loads up it display this control, which resides in the Views category, Tasks.xaml.

<Grid Margin="6">
    <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition Width="2*"/>
    </Grid.ColumnDefinitions>
    <Border Style="{StaticResource OuterBorderStyle}" Margin="0,0,6,0">
        <telerikNavigation:RadTreeView x:Name="tvwCategories" ItemsSource="{Binding TaskCategories}" SelectedItem="{Binding SelectedTaskCategory, Mode=TwoWay}"/>
    </Border>
    <Controls:GridSplitter Width="6" Opacity="0"/>
    <Border Style="{StaticResource OuterBorderStyle}" Grid.Column="1">
        <Grid>
            <TextBlock Text="Please select a category." Visibility="{Binding ShowSelectMessage, Converter={StaticResource BooleanToVisibilityConverter}}"/>
            <TextBlock Text="The selected category has no tasks." Visibility="{Binding ShowNoTasksMessage, Converter={StaticResource BooleanToVisibilityConverter}}"/>
            <telerikGridView:RadGridView ItemsSource="{Binding Tasks}" SelectedItem="{Binding SelectedTask, Mode=TwoWay}" Visibility="{Binding ShowGridView, Converter={StaticResource BooleanToVisibilityConverter}}" AutoGenerateColumns="False">
                <telerikGridView:RadGridView.Columns>
                    <telerikGridView:GridViewDataColumn Header="Name" DataMemberBinding="{Binding Name}" Width="3*"/>
                    <telerikGridView:GridViewDataColumn Header="Description" DataMemberBinding="{Binding Description}" Width="*"/>
                    <telerikGridView:GridViewDataColumn Header="Due" DataMemberBinding="{Binding DueDate}" DataFormatString="{}{0:d}" Width="80"/>
                    <telerikGridView:GridViewDataColumn Header="Completed" DataMemberBinding="{Binding CompletionDate}" DataFormatString="{}{0:d}" Width="80"/>
                </telerikGridView:RadGridView.Columns>
                <telerikNavigation:RadContextMenu.ContextMenu>
                    <telerikNavigation:RadContextMenu Opened="GridContextMenuOpened">
                        <telerikNavigation:RadMenuItem Header="Move To">
                            <telerikNavigation:RadMenuItem Header="Inbox" Command="{Binding MoveToCommand}" CommandParameter="{Binding TaskCategoryInbox}" Visibility="{Binding IsMoveToInboxCommandAvailable, Converter={StaticResource BooleanToVisibilityConverter}}"/>
                            <telerikNavigation:RadMenuItem Header="Actions" Command="{Binding MoveToCommand}" CommandParameter="{Binding TaskCategoryActions}" Visibility="{Binding IsMoveToActionsCommandAvailable, Converter={StaticResource BooleanToVisibilityConverter}}"/>
                            <telerikNavigation:RadMenuItem Header="Waiting" Command="{Binding MoveToCommand}" CommandParameter="{Binding TaskCategoryWaiting}" Visibility="{Binding IsMoveToWaitingCommandAvailable, Converter={StaticResource BooleanToVisibilityConverter}}"/>
                            <telerikNavigation:RadMenuItem Header="Someday" Command="{Binding MoveToCommand}" CommandParameter="{Binding TaskCategorySomeday}" Visibility="{Binding IsMoveToSomedayCommandAvailable, Converter={StaticResource BooleanToVisibilityConverter}}"/>
                            <telerikNavigation:RadMenuItem Header="Ticklers" Command="{Binding MoveToCommand}" CommandParameter="{Binding TaskCategoryTicklers}" Visibility="{Binding IsMoveToTicklersCommandAvailable, Converter={StaticResource BooleanToVisibilityConverter}}"/>
                            <telerikNavigation:RadMenuItem Header="Reference" Command="{Binding MoveToCommand}" CommandParameter="{Binding TaskCategoryReference}" Visibility="{Binding IsMoveToReferenceCommandAvailable, Converter={StaticResource BooleanToVisibilityConverter}}"/>
                        </telerikNavigation:RadMenuItem>
                    </telerikNavigation:RadContextMenu>
                </telerikNavigation:RadContextMenu.ContextMenu>
            </telerikGridView:RadGridView>
        </Grid>
    </Border>
</Grid>

It looks like a lot of code, but it's no that bad. It doesn't look as daunting in VisualStudio where it doesn't wrap, and a lot of the code is for the RadContextMenu.

At the top level we have a Grid with 2 columns. The Width="2*" attribute on the second column makes it twice as wide as the first. Each column contains a Border control with a style that gives it a black border, rounded corners and a bit of padding (see OuterBorderStyle in Assets/Styles/Styles.xaml). The first column also has a bit of margin on the right side where a GridSplitter will allow us to resize the two sides if we'd like.

The Border in the first column contains one element, the RadTreeView:

<telerikNavigation:RadTreeView x:Name="tvwCategories" ItemsSource="{Binding TaskCategories}" SelectedItem="{Binding SelectedTaskCategory, Mode=TwoWay}"/>

Notice that the ItemsSource is bound to a property called TaskCategories in our view model (yes, we are continuing to use the MVVM pattern), and the SelectedItem is bound to a property called SelectedTaskCategory. We'll look at the view model shortly.

The Border in the second column contains three controls, two TextBlocks and the RadGridView. This is just a partial listing:

<Grid>
    <TextBlock Text="Please select a category." Visibility="{Binding ShowSelectMessage, Converter={StaticResource BooleanToVisibilityConverter}}"/>
    <TextBlock Text="The selected category has no tasks." Visibility="{Binding ShowNoTasksMessage, Converter={StaticResource BooleanToVisibilityConverter}}"/>
    <telerikGridView:RadGridView ItemsSource="{Binding Tasks}" SelectedItem="{Binding SelectedTask, Mode=TwoWay}" Visibility="{Binding ShowGridView, Converter={StaticResource BooleanToVisibilityConverter}}" AutoGenerateColumns="False">
...
    </telerikGridView:RadGridView>
</Grid>

First let's talk about the RadGridView. It's ItemsSource is bound to a property in our view model called Tasks, and SelectedItem is bound to a property called SelectedTask.

Now the Visibility of each of the three elements is determined by binding to properties in our view model. Notice the use of the BooleanToVisibilityConverter that Telerik kindly provides in it's Telerik.Windows.Controls namespace, so we don't have to add our own converter class. This converter is declared as a static resource in App.xaml so we can use it throughout our app:

<telerikControls:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>

 

The code-behind

So now let's take a look at the code-behind, Tasks.xaml.cs:

public partial class Tasks
{
    public Tasks()
    {
        InitializeComponent();
        var viewModel = new TasksViewModel();
        DataContext = viewModel;
    }
 
    private void GridContextMenuOpened(object sender, RoutedEventArgs e)
    {
        Utils.GridContextMenuOpened(sender, e);
    }
}

There is hardly anything to it, which is what we want when using the MVVM pattern. In the constructor we insantiate our view model class and set it as the DataContext of our UserControl. The only other thing we have to do is include a method that is called by our RadContextMenu. You can take a look at the GridContextMenuOpened method in the Utils classs, but this simply tells the RadGridView that the row that we right-click on should become selected. You'll see this same code in other Telerik samples. I just put it in a Utils class so I can reuse it across multiple RadGridViews in my UI.

On the RadContextMenu you'll see where it is called:

<telerikNavigation:RadContextMenu Opened="GridContextMenuOpened">

 

The commands

OK, the main thing we're here to look at are the commands, so let's look at the RadMenuItems:

<telerikNavigation:RadMenuItem Header="Inbox" Command="{Binding MoveToCommand}" CommandParameter="{Binding TaskCategoryInbox}" Visibility="{Binding IsMoveToInboxCommandAvailable, Converter={StaticResource BooleanToVisibilityConverter}}"/>
<telerikNavigation:RadMenuItem Header="Actions" Command="{Binding MoveToCommand}" CommandParameter="{Binding TaskCategoryActions}" Visibility="{Binding IsMoveToActionsCommandAvailable, Converter={StaticResource BooleanToVisibilityConverter}}"/>
<telerikNavigation:RadMenuItem Header="Waiting" Command="{Binding MoveToCommand}" CommandParameter="{Binding TaskCategoryWaiting}" Visibility="{Binding IsMoveToWaitingCommandAvailable, Converter={StaticResource BooleanToVisibilityConverter}}"/>
<telerikNavigation:RadMenuItem Header="Someday" Command="{Binding MoveToCommand}" CommandParameter="{Binding TaskCategorySomeday}" Visibility="{Binding IsMoveToSomedayCommandAvailable, Converter={StaticResource BooleanToVisibilityConverter}}"/>
<telerikNavigation:RadMenuItem Header="Ticklers" Command="{Binding MoveToCommand}" CommandParameter="{Binding TaskCategoryTicklers}" Visibility="{Binding IsMoveToTicklersCommandAvailable, Converter={StaticResource BooleanToVisibilityConverter}}"/>
<telerikNavigation:RadMenuItem Header="Reference" Command="{Binding MoveToCommand}" CommandParameter="{Binding TaskCategoryReference}" Visibility="{Binding IsMoveToReferenceCommandAvailable, Converter={StaticResource BooleanToVisibilityConverter}}"/>

As we mentioned earlier, each one is bound to MoveToCommand (in our view model, naturally), but each one has a CommandParameter property that is once again bound to properties in our view model. When the command is invoked, this parameter will determine which category to move the task to. Also notice that each RadMenuItem has a Visibility property that is bound to a property in our view model. The reason for this is if we are looking at the tasks for a certain category, Inbox for example, it wouldn't make sense for Inbox to show up in the context menu. How can we move a task to the Inbox if it's already in the Inbox, right?

The view model

As I've talked about in my other blog posts, with the MVVM pattern the view model is the brains of the operation. It is responsible for retrieving the data, showing and hiding various UI elements, and responding when the user interacts with something in the user interface. Because everything lives there, it can be tested independently of the UI, and the same view models could support a different UI, perhaps for a Windows Phone 7 version of an application.

In our view model constructor, we do two things. Create an instance of the DataContext object (this is the WCF RIA Services object that is responsible for retrieving and updating data) and retrieve the TaskCategories.

public TasksViewModel()
{
    DataContext = new DataContext();
    LoadData();
}
 
private void LoadData()
{
    LoadTaskCategories();
}

 

When the categories have loaded (via WCF RIA Services), we assign them to the TaskCategories property, and fire an OnPropertyChanged notification. This tells the RadTreeView to re-bind, and the categories appear in the tree:

public LoadOperation<TaskCategory> LoadTaskCategories()
{
    // Get the data via WCF RIA Services. When the call has returned, called OnTaskCategoriesLoaded.
    return DataContext.Load(DataContext.GetTaskCategoriesQuery(), OnTaskCategoriesLoaded, false);
}
 
void OnTaskCategoriesLoaded(LoadOperation<TaskCategory> lo)
{
    TaskCategories = lo.Entities;
 
    // Notify the UI that TaskCategories property has changed
    this.OnPropertyChanged(m => m.TaskCategories);
}

Now when the user selects a category in the RadTreeView, the setter of the SelectedTaskCategory property is called. It stores the selected category, sends a bunch of notifications that determine whether UI elements should be visible or non-visible, and loads the tasks for the selected category:

public TaskCategory SelectedTaskCategory
{
    get { return _selectedTaskCategory; }
    set
    {
        _selectedTaskCategory = value;
        this.OnPropertyChanged(m => m.SelectedTaskCategory);
        this.OnPropertyChanged(m => m.ShowSelectMessage);
        this.OnPropertyChanged(m => m.IsMoveToInboxCommandAvailable);
        this.OnPropertyChanged(m => m.IsMoveToActionsCommandAvailable);
        this.OnPropertyChanged(m => m.IsMoveToWaitingCommandAvailable);
        this.OnPropertyChanged(m => m.IsMoveToSomedayCommandAvailable);
        this.OnPropertyChanged(m => m.IsMoveToTicklersCommandAvailable);
        this.OnPropertyChanged(m => m.IsMoveToReferenceCommandAvailable);               
        LoadTasks();
    }
}

 

Once again the Tasks are loaded via WCF RIA Services and the return collection is assigned to the Tasks property. Notifications are then sent to the UI to determine which items should be visible (based on whether any tasks are returned:

public LoadOperation<Task> LoadTasks()
{
    // Get the data via WCF RIA Services. When the call has returned, called OnTasksLoaded.           
    return DataContext.Load(DataContext.GetTasksByCategoryQuery(SelectedTaskCategory.ID), OnTasksLoaded, false);
}
 
void OnTasksLoaded(LoadOperation<Task> lo)
{
    Tasks = lo.Entities;
 
    // Notify the UI that Tasks property has changed
    this.OnPropertyChanged(m => m.Tasks);
    this.OnPropertyChanged(m => m.ShowNoTasksMessage);
    this.OnPropertyChanged(m => m.ShowGridView);
}

 

How the commands work

We saw earlier how each of the RadMenuItems in the RadContextMenu have a CommandParameter that is bound to a property in the view model. These values are actually enums of type TaskCategoryEnum. These can be found in Core/Enums.cs:

public enum TaskCategoryEnum
{
    Inbox = 1,
    Actions = 2,
    Waiting = 3,
    Someday = 4,
    Ticklers = 5,
    Reference = 6
}

Each of these enums has an int value that corresponds to the id of that category in the database's TaskCategory table:

TaskCategory table

As I mentioned in my previous post, I have chosen to use the MVVM Light Toolkit's RelayCommand class for my commands. In that post the RelayCommand I used for saving did not pass a parameter. In this case, we do pass a TaskCategoryEnum:

private RelayCommand<TaskCategoryEnum> _moveToCommand;
public RelayCommand<TaskCategoryEnum> MoveToCommand
{
    get { return _moveToCommand ?? (_moveToCommand = new RelayCommand<TaskCategoryEnum>(OnMoveTo)); }
}

When one of the RadMenuItems is clicked, the command is invoked, and the OnMoveTo method is called. This obtains the int value of the TaskCategoryEnum that was passed as a CommandParameter, sets the TaskCategoryID property of the SelectedTask (the one the user right-clicked on) to that int value, and uses WCF RIA Services to save the task (effectively 'moving' it to a different category):

public void OnMoveTo(TaskCategoryEnum taskCategoryEnum)
{
    // Set the TaskCategoryID to that of the item that was selected from the RadContextMenu
    SelectedTask.TaskCategoryID = Convert.ToInt32(taskCategoryEnum);
    DataContext.SubmitChanges(MoveToCompleted, null);
}
 
public virtual void MoveToCompleted(SubmitOperation so)
{
    // Only show the tasks for the selected category
    Tasks = Tasks.Where(t => t.TaskCategoryID == SelectedTaskCategory.ID);
 
    // Inform the UI that the Tasks collection and HasTasks property has changed
    this.OnPropertyChanged(m => m.Tasks);
    this.OnPropertyChanged(m => m.ShowNoTasksMessage);
    this.OnPropertyChanged(m => m.ShowGridView);
}

 

Wrap up

In part 1 of the Commands post we implemented a very simple SaveCommand and bound it to two UI controls. In this part our code became a bit more complex and demonstrated how we can bind a command to multiple context menu items, allowing us to move items from one category to the next.

Commands are a huge addition to Silverlight 4, and I hope you can see the power of leveraging them in your user interfaces!

18 Comments

  • Amit 19 Apr

    Database code did not run, I use SQL Express 2005.  If possible, please provide sql database file in examples, I cannot run sql script on my machine so I cannot run demo.


    Also, when is TaskIt source code/application coming?  You post for over a month talking about app but I see no source code. :(
  • Ross 19 Apr
    Sorry for the issues Amit. Please try downloading the source again and see if it works out any better for you this time. I was using SQL Express 2008 and the problem may be that it supports a type called 'Date' and I don't believe 2005 does.

    Task-It is still a work-in-progress, so I can't say exactly when the source will be available. It's been quite challenging updating things through the myriad of new Silverlight-related releases lately, and with each update comes a new set of bugs. :-)
  • Amit 20 Apr
    So how do I run code with SQL Express 2005?  I cannot install 2008 and our host will not support 2008 for long time.  Why not release code now and update as needed?
  • Ross 20 Apr
    Hi Amit,

    You should no longer need SQL Express 2008 or SQL Server 2008. You simply need to create a database in SQL Express 2005 and then run that .sql script that I included in the Database directory against it in Management Studio. If you don't already have Management Studio, you can get it here:

    http://www.microsoft.com/downloads/details.aspx?FamilyId=C243A5AE-4BD1-4E3D-94B8-5A0F62BF7796&displaylang=en
  • Ross 20 Apr
    Oh, and the database you create in SQL Express 2005 should be called TaskItCommands.

    Ross
  • Amit 20 Apr
    I cannot run SSMS, admin rule restricts access.  Can you provide sql server database file so example can unzip and run?
  • Ross 20 Apr
    Try downloading it here and let me know if you run into any problems:

    http://bit.ly/9BFN3R

    Ross
  • jacky 21 Apr

    When i compile the project and run it ,in treeview show "TaskCategory:1"... not show "Inbox"...

    I use VS 2010 RTM+Silverlight 4 Tools

    How can i fix the problem !

    JACKY
  • Bruce Krasnof 22 Apr
    Ross, love your posts.  I'm a .net programmer working at a university but a newbie with Silverlight, MEF, RIA, OpenAcess or EF, etc.   Been feeling overwhelmed but excited about the new possibilities with Silverlight for business apps, the whole MEF and MVVM approach and very impressed with the Telerik suite.  I think your Task-IT blogs and videos are the best way for me to dive in and try building a Silverlight 4 prototype the right way with some nice Telerik polish.   I live in NH but work in MA, do you ever present some of this stuff in person at any silverlight or .net user groups that you'd recommend?  thanks, Bruce
  • Ross 22 Apr
    Jacky,

    I'm a bit puzzled as to why you are not seeing the task category names in the RadTreeView. If you have all of the latest stuff, which it sounds like you do, the code generation that WCF RIA Services provides should have push the override of the ToString method on the TaskCategory object across to the client. Please view all files in your Silverlight project (Commands2), expand Generated_Code, expand Models, expand Shared, and see if there is a class in there called TaskCategory.shared.cs. If you have those folders and files, you should see the ToString override in that class.

    In the meantime, a workaround is to add  DisplayMemberPath="Name" to your RadTreeView tag. That should fix your problem, but I prefer using the shared code override of ToString so that you don't have to do that, and will blog about this technique in the next week or two.

    Ross
  • Ross 22 Apr
    Hi Bruce,

    Funny, I actually work in NH and work in MA as well.

    I would've spoken at the NH .NET User Group in Nashua (http://www.nhdn.com/DNN/) last night if I didn't have Red Sox tickets. If you'd like to see me there, feel free to bug Pat Tormey (the leader of the group) about getting me on their upcoming agenda.

    I will be speaking at the New England Visual Basic Professionals group here in Waltham (http://www.nevb.com/) on May 6th, but that will be a bit of a stretch because I haven't done VB.NET in quite a while (will have to convert some of my small sample apps). The group sounds very new to Silverlight though, so I probably won't get too deep into anything.

    Ross
  • Ross 22 Apr
    By the way Bruce, meant to pass along a very sincere thanks for your nice words. I'm glad that you're finding the posts helpful.

    Rosss
  • Bruce Krasnof 22 Apr
    Hi Ross, that's funny, glad no toll booths yet on the border.   I haven't been to a user's group in a long while, maybe silverlight 4 is a good excuse to start going, I'll take a look at the Nashua group.  I live in Windham.

    Talked to some .net programmers here who have a lot of legacy Foxpro thick client apps and experience and use Foxpro as a backend,  might be able to get them excited about Silverlight with RIA Services and MEF and EF or OpenAccess. 

    Maybe I can build a proof of concept using the same architecture as Task-It but is more relevant to these folks ( univ. admissions specialty).

    I'd love to build something that shows a grid where they can filter and drag applicants to a panel, and then simulate sending a custom email to the selected applicants..could show off a lot of RADControls nicely...the fancy grid, nice filtering, drag and drop between containers, panel with richedit text box for the email composition, and powered by MEF, RIA Services and a data model with either EF or OpenAccess.

    Might be too ambitious but that would open some eyes here at the school on both the new .net 4 stuff and RadControls.  I love the idea of not having to write sql plumbing anymore, and having  rich data binding using just C# and xaml.
  • Steve Davison 22 Apr
    Ross:  First off let me say thanks for these informative posts; my coworkers and I are just digging into Silverlight 4/EF4 and your blog has been great to follow (can't wait for the final code!).  That said, I've run into a couple of issues:

    1.  I also saw the same behavior as JACKY posted about.  I checked the TaskCategory.shared.cs class and it DOES have an override for ToString() but it doesn't appear to be getting used, as even watches are displaying the original ToString() results.  Your alternate suggestion of setting DisplayMemberPath does work fine, however, but I'd be interested if you have any ideas why the ToString() override is not working.

    2.  The RadTreeView tag in Tasks.xaml has the following property set:
    SelectedItem="{Binding SelectedTaskCategory, Mode=TwoWay}  
    For my own interest, I want to set the last Category in TaskCategories as the SelectedTaskCategory during the OnTaskCategoriesLoaded event, like so:
    TaskCategories.Last().Selected = true
    While the OnPropertyChanged calls are correctly fired (and the grid filled in correctly), it doesn't appear that the RadTreeView is setting the SelectedItem correctly, even though it's in TwoWay binding mode (i.e. the brush that indicates the item is selected is not being drawn).  If I click on an item in the RadTreeView, the SelectedItem is set correctly (and the brush is shown).  Any ideas why the RadTreeView SelectedItem binding is not working?

    Thanks and looking forward to your next blog post!
  • JACKY 23 Apr
    Hi Ross

    Thamk you for your help , i use DisplayMemberPath it work !

    but interested is when is use shared cod  the ToString() override is not working.

    maybe i miss something ,tying fix this problem.

    JACKY
  • Ross 23 Apr
    Bruce, sounds like you have a lot of fun ahead of you working w/ Silverlight 4 and our RadControls. Glad to have you on the bandwagon!

    Jacky and Steve, I wish I could explain why the ToString() override in shared code is not working for you. I've been using this technique for quite a while and never had a problem. I prefer not to use DisplayMemberPath because it is not strongly-typed, and it helps in keeping the XAML a little cleaner. I use this ToString() override technique quite a lot in my Task-It application, so it'll be interesting to see if other folks have the same issue when I make the source code available for download next week. This reminds me of all the times in the past when a QA person said that they had a bug, and the developer's response was, "it works on my machine" (I never took that attitude by the way).

    Bruce, with regard to the SelectedItem binding on the RadTreeView, that is a tricky one. I've run into the same thing myself and need to further investigate. I'll let you know what I find out.

    Ross
  • JACKY 24 Apr
    Hi Ross

    I fix ToString() override in shared code is not work issuse,just in TaskCategory.shared.cs replace "return Name;" to "return this.Name;"

    so the before code  in  TaskCategory.shared.cs is

    namespace Commands2.Web
    {
        public partial class TaskCategory
        {
            public override string ToString()
            {
                return Name;
            }
        }
    }

    and then replace after code in TaskCategory.shared.cs is
    namespace Commands2.Web
    {
        public partial class TaskCategory
        {
            public override string ToString()
            {
                return Name;
            }
        }
    }


    ha ~ very simple and interest...

    JACKY
  • Ross 26 Apr
    Thanks for the solution Jacky. I can't explain why this would be necessary, as any refactoring tool will tell you that using 'this.' is unnecessary, unless you are calling an extension method. In this case we are simply overriding the default behavior of ToString(), which is what is called when an object is data bound to something like a RadTreeViewItem.

    Odd that has always worked fine for me without this, but I guess I'll add it so that you and others don't experience these issues in the future.

    Ross

Add comment

  1. Formatting options
       
     
     
     
     
       
  2. (optional, emails won't be shown on public pages)
  3. (optional)