Miguel A. Castro's Blog

# Friday, November 19, 2010

I’m going to be a little different on this posting and talk about an actual pay-product that is totally worth your while to look at.  The product I’m talking about is called DocumentX 2010 and it’s by a company called Innovasys.

I’ve been dealing with Innovasys for a long time now.  Back when I first started developing CodeBreeze, I was on the hunt for a good help authoring system in order write a quality help system for my own applications and I came across the original Document X.  First, let me tell you what Document X does.  Put simply, it lets you develop MSDN-style documentation for your APIs and object models.  It comes with its own full-feature IDE, but also fully integrates with Visual Studio and also imports <summary>-style documentation directly from your code.  Document X has the concept of content files that let you define all the documentation for a specific assembly, then by creating a project file, you can important as many content files as you want.  The end-result is a help file that can incorporate multiple assemblies.  Innovasys also makes a sister product called Help Studio, which is used to author complete help systems for your applications.   With Help Studio you can create any number of topics, glossaries, and custom tables-of-content.  Into a Help Studio project, you can important a Document X project, giving you a complete single help file for your application that contains all your user-help, the way you designed it, as well as the object-model documentation in MSDN format.

The reason I felt it important to share my experience with you is because it was a unique one.  Using the Document X product, along with its sister application, Help Studio, I was inspired to take certain approaches during the design and development of CodeBreeze.  As I used the product suite, I noticed that every part of the application can be customized, including the templates for the help being generated.  The usage of context menus, short-cuts, tabbed-MDI, and other UX details was extensive and I became very impressed with the way the suite was built.  The guys at Innovasys seem to go out of their way to provide the best and most intuitive user experience possible.  Normally, the task of creating documentation can be quite tedious, but the best compliment I can give Innovasys is that it’s a task that I actually enjoy.

FullDocXApp

The more I used the Document X and Help Studio product suite, the more I found myself changing things in CodeBreeze to provide a better and better user experience.  It became quite frustrating, but in a good way Smile.  A couple of years later, at the Los Angeles PDC, I got the opportunity to meet the Innovasys team after exchanging emails when them for a while and they were as pleasant I person as they were on-line. 

Document X is on its 2010 release and HelpStudio is about to be released as the 2011 version, both are written in WPF, and based on all the conversations I’ve had with Innovasys, the applications have a solid architecture and do their predecessors proud in all the usual attention to detail.

I’ve had the opportunity to dialog quite a bit with Innovasys and it’s no surprise their products are built so well.  It such a treat getting into real geeky conversations with these guys.  Recently, our conversations have been about WPF, MVVM, abstractions, templates, and other great technologies used in the latest versions of their products.  The new versions of Document X and Help Studio are built entirely in WPF and I gotta say that once again, their proving an inspiration in the next version of CodeBreeze, to be released sometime next year.

Be sure to check out their apps at www.innovasys.com, where you can download a free trial for all their products.

Keep up the great work guys.

Until next time…

Friday, November 19, 2010 5:07:19 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] - - Follow me on Twitter

# Wednesday, November 03, 2010

Oh boy, this one just drove me insane for over two hours.

First of all, I have a ViewModel that is bound to a user control on a “start page” of my application which is designed to show a Recent Files list.  The displaying of this list worked just fine.  The ViewModel encapsulates a command member whose execution method is within the ViewModel class itself.

The command is declared and initialized in my view model like this:

 

public override void InitializeViewModel()
{
    FileSelectedCommand = new DelegateCommand<Uri>(FileSelectedCommand_Execute);
    base.InitializeViewModel();
}

public DelegateCommand<Uri> FileSelectedCommand { get; protected set; }

 

The command’s execution method looks like this, but what it’s doing is not what’s important here.

 

void FileSelectedCommand_Execute(Uri arg)
{
    if (arg != null)
    {
        _RecentDocManager.NotifyDocumentOpened(arg);
        OnFileSelected(new FileLocationEventArgs(arg));
    }
}

 

What is important is the argument that it’s set up to receive.  Notice that in this case, it’s a URI, which is the exact type to which the CommandParameter argument in my view is bound:

 

<src:StartPageViewBase.Resources>
    <shared:CommandReference x:Key="fileSelectedCommand" Command="{Binding Path=FileSelectedCommand}" />
    <ResourceDictionary x:Key="dict1">
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="/Views/SharedResources.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</src:StartPageViewBase.Resources>
<Grid>
    <ItemsControl ItemsSource="{Binding Path=Documents}" DataContext="{Binding}" Grid.IsSharedSizeScope="True" Margin="5,5,5,5">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Button Style="{DynamicResource {x:Static ribbon:RibbonStyles.ButtonKey}}" HorizontalContentAlignment="Left"
                        Command="{StaticResource fileSelectedCommand}" CommandParameter="{Binding Path=Location}">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto" SharedSizeGroup="Name" />
                            <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>
                        <TextBlock Grid.Column="0" Text="{Binding Path=Name}" Margin="0,0,3,0" />
                        <TextBlock Grid.Column="1" Text="{Binding Path=Location}" ToolTip="{Binding Path=Location}" Margin="0,0,3,0" />
                    </Grid>
                </Button>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Grid>

 

The problem that drove me crazy was the fact that originally my command was declared with a string in the generic type, and in the case of a delegate-command (or a relay-command as it is otherwise known), the generic type defines the type that the potential argument will be.  The CommandParameter argument shown above is bound to a data context member called Location, and this member is a URI, not a string.

The simple mistake of having declared FileSelectedCommand as DelegateCommand<string>, completely disbled the button to which the command is bound.

Uhhhhhhg!

---------------------

On another topic, I haven’t done a very good job regularly posting the “This Week In Code” series.  I’m not going to stop doing it, and I promise to try to get back to making it weekly as in the first four, but I’ve been traveling a lot lately and could never guarantee where I’m going to be from one week to the next.

 

Until next time…

Wednesday, November 03, 2010 7:51:55 PM (Eastern Daylight Time, UTC-04:00)  #    Comments [0] - - Follow me on Twitter

# Wednesday, September 29, 2010

My good buddy, Wally McClure was just featured in an article for “Application Development Trends” on iPhone development using Mono-Touch.  Wally has been speaking on this around the country, and I was actually an audience member in CodeStock this year.  I gotta say, I found the topic informative an intriguing, since I fall into the very category that he targets, .NET devs with iPhones.

It’s definitely a topic worth talking about since it brings together to really great platforms.  The article is not a how-to, it’s an interview conducted by Michael Desmond (isn’t that one of the former Monkees?), but it’s a nice read.

Check out the article at http://adtmag.com/articles/2010/09/29/monotouch-qa-with-wallace-mcclure.aspx.

Wednesday, September 29, 2010 2:24:59 PM (Eastern Daylight Time, UTC-04:00)  #    Comments [0] - - Follow me on Twitter

# Friday, September 24, 2010

One of my latest challenges involved the topic of WPF sizing.  I’m referring to the manipulation of control widths in relation to their parent widths.  Most books tell you that this happens automatically, but I’m here to say otherwise gentle reader.  Now, I am fully prepared to admit that I may have missed something so if you’re a WPF expert out there and you think there is a better way to do what I’m going to show you, please respond. 

So here is my situation:

I have a window (user control actually, but then almost everything is in most WPF applications).  My window defines a grid with two columns, each which will contain a user control of their own.  It looked something like this:

 

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="300" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <src:Control1 Grid.Column="0" x:Name="ctlControl1" DataContext="{Binding Path=Control1ViewModel}" />
    <src:Control2 Grid.Column="2" x:Name="ctlControl2" />
</Grid>

The user control called Control1 contains a ListView control which defined an ItemTemplate to construct the content structure of each item.  The effect I wanted was to show the data for each item in read-only mode and provide an “edit” icon on each item.  Pressing it would convert that item to editable textboxes.  I got that working fine by providing two Grids inside my data template, setting one of them invisible, then using commanding on the button icons to change the view-model state to switch the Visibility of each grid was bound – worked like a charm and is a really nice effect.

My problem was that both the TextBlock and TextBox controls in each item view sized to its contents, then the widest one became the width of the actual ListView that contained everything.  Originally, the column that contained this entire user control (defined above) was set to Auto, so of course it would widen to the width of the longest text control.  This totally sucked.

I added a splitter to the grid in the user control that contained the other two controls and the results at first were weird.  I took the recommendation of most books and added the GridSplitter to its own column (set to Auto width) at first.  This enabled me to resize the grid columns but by then, the content user control’s width was already set and it would not resize along with my resize-drag.  Dragging the splitter to the right, left the contents of the first column fixed, and dragging to the left basically didn’t work past the already fixed-width of the first column.  I fixed this by adding the GridSplitter as the last control on the same column as one of the controls, like this:

 

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="300" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <src:Control1Grid.Column="0" x:Name="ctlControl1" DataContext="{Binding Path=Control1ViewModel}" />
    <GridSplitter ResizeDirection="Columns" Grid.Column="0" Width="3" />
    <src:Control2 Grid.Column="2" x:Name="ctlControl2" />
</Grid>

 

Now when I drag the splitter, the columns follow along the resize in both directions; however the TextBlock and TextBox controls in my ListView remain sized to their contents and would not stretch in either direction.  This still totally sucked.

After playing around significantly with this, I discovered that the ListView itself was sizing and resizing dynamically as I dragged my splitter so I needed to get the contents of each item to size similarly.  The solution was to bind the Width of each of my TextBlock and TextBox items to the width of the ListView in which they were contained.  I gave the ListView control a name (I don’t normally name my controls since most of my work happens in the View-Model anyway), then set the Width property of the contained controls like this:

 

<ListView Name="lvw1" ItemsSource="{Binding}" DataContext="{Binding Path=VuewModelPropertyGoesHere}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <Grid>
                <Grid Visibility="{Binding Path=EditMode, Converter={StaticResource notEditModeVisibilityConverter}, Mode=OneWay}">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="25" />
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="25" />
                        <RowDefinition Height="10" />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>
                    <TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding Path=Name}" TextWrapping="Wrap" HorizontalAlignment="Stretch"
Width="{Binding ElementName=lvw1, Path=ActualWidth}" Margin="0,0,5,0" /> <TextBlock Grid.Row="1" Grid.Column="0" Text="{Binding Path=Description}" TextWrapping="Wrap" HorizontalAlignment="Stretch"
Width="{Binding ElementName=lvw1, Path=ActualWidth}" Margin="0,0,5,0" /> . . . </Grid> <Grid Visibility="{Binding Path=EditMode, Converter={StaticResource editModeVisibilityConverter}, Mode=OneWay}"> <Grid.RowDefinitions> <RowDefinition Height="25" /> <RowDefinition Height="Auto" /> <RowDefinition Height="*" /> <RowDefinition Height="10" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <TextBox Grid.Row="0" Grid.Column="0" Text="{Binding Path=Name, UpdateSourceTrigger=PropertyChanged}"
Width="{Binding ElementName=lvw1, Path=ActualWidth, Mode=OneWay}" Margin="0,0,5,0" VerticalAlignment="Center" /> <TextBox Grid.Row="1" Grid.Column="0" Text="{Binding Path=Description, UpdateSourceTrigger=PropertyChanged}"
TextWrapping="Wrap" AcceptsReturn="True" MaxLines="3" MinLines="3" VerticalScrollBarVisibility="Auto"
Width="{Binding ElementName=lvw1, Path=ActualWidth, Mode=OneWay}" Margin="0,0,5,0" VerticalAlignment="Center" />

 

This totally fixed my problem… almost.  While the binding worked perfectly, the look I got left one little detail to be desired.  You see, now the width of the textboxes as equal to the width of the ListView.  This made their right edge disappear, and no margin and padding setting would fix it.

What I needed to do is set the width of the controls to slightly less than the width of the ListView; 10 pixels less to be exact.  Apparently in WPF, you either bind or you do not bind; not a combination of the two.  And you certainly cannot do mathematics in the XAML.  So what to do?

At this point, I had become quite comfortable with the idea of a type-converter so this is the first thing that sprung into my mind.  I created a type converter that I could use in this binding.  The job of the type converter would be to take the incoming width, and rather than convert it to another type, simply adjust by a certain amount and return that number.  And what amount you ask?  Well, the type converter gives you a “parameter’ argument than you can fill in the XAML, so the answer is: any amount I desire.

The end-result worked and looked great.  Here’s the type converter code:

 

public class WidthToParentConverter : IValueConverter
{
    object IValueConverter.Convert(object value, Type targetType, object parameter,
        System.Globalization.CultureInfo culture)
    {
        double width = (double)value;
        double adjustment = Convert.ToDouble(parameter);

        return width + adjustment;
    }

    object IValueConverter.ConvertBack(object value, Type targetType, object parameter,
        System.Globalization.CultureInfo culture)
    {
        double width = (double)value;
        double adjustment = Convert.ToDouble(parameter);

        return width - adjustment;
    }
}

 

And here’s the adjusted XAML for the textboxes:

 

<TextBox Grid.Row="0" Grid.Column="0" Text="{Binding Path=Name, UpdateSourceTrigger=PropertyChanged}"
Width="{Binding ElementName=lvw1, Path=ActualWidth, Converter={StaticResource widthToParentConverter}, ConverterParameter=-10, Mode=OneWay}"
Margin="0,0,5,0" VerticalAlignment="Center" /> <TextBox Grid.Row="1" Grid.Column="0" Text="{Binding Path=Description, UpdateSourceTrigger=PropertyChanged}"
TextWrapping="Wrap" AcceptsReturn="True" MaxLines="3" MinLines="3" VerticalScrollBarVisibility="Auto"
Width="{Binding ElementName=lvw1, Path=ActualWidth, Converter={StaticResource widthToParentConverter}, ConverterParameter=-10, Mode=OneWay}"
Margin="0,0,5,0" VerticalAlignment="Center" />

 

 

I struggled with this for a quite a bit, mainly because of inexperience, but now I know exactly what to do in this situation and I hope sharing it helps some of you as well.

 

Until Next Time…

Friday, September 24, 2010 4:38:46 PM (Eastern Daylight Time, UTC-04:00)  #    Comments [0] - - Follow me on Twitter
Dev Stuff | WPF
# Tuesday, September 14, 2010

9-14-2010 12-19-18 AMFor those of you that have downloaded my Pipeline Framework (on the downloads section) as seen in my last DNR-TV episode, there seems to be a weird block being put on the app.config file when the code unzips.

This problem is being manifested as a constructor exception in the XAML of the primary window of the client project, though the problem is not really there.

Though I have no idea how to avoid this, the fix is easy.  Find the app.config file in the PipelineFramework.Client project, right-click on it and select properties.  In the lower-right corner, click on the “Unblock” button and that’s it.

 

Sorry for the inconvenience.  If anyone knows a way to avoid having to do this altogether, please let me know.

Tuesday, September 14, 2010 12:16:20 AM (Eastern Daylight Time, UTC-04:00)  #    Comments [1] - - Follow me on Twitter

Search
Me & My Flair

Read all about me here.
Download my Resume here.

Check out where I am here.
 
Click on logos above for profiles.
Archive
<November 2010>
SunMonTueWedThuFriSat
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011
Statistics
Total Posts: 40
This Year: 0
This Month: 0
This Week: 0
Comments: 93