I've been working on and off for the last few years since I started programming on an MU* client which I call Amuse.
It took creating a ticking clock in the form of a CodePlex project creation (you get 30 days to set up your project before it is either deleted or you publish it) for me to really dive on in and clean out the code, but I did it and I'm pleased to make it public today.
The current version as it looks right now isn't that impressive to the eyes but I've spent a lot of time making sure the underlying code for it is sound and should help give me less headaches as I now focus on moving it towards a 1.0 state, complete with a decoupled user interface so that when the time is right, a far nicer one can replace the one you can see here.
More posts as I develop this application should follow in the future, and I may well link this blog to the the project via an RSS link if I start using it a lot to discuss the development of Amuse.
For now anyway, check out the Project Homepage and if by chance you enjoy some classic text based RPG's, try it out and see how it handles.
No posts in.. quite a while. Oh dear. I really should stop trying to do complex things like trying to do a series and just do what I set out to do, post little discoveries of 'oh, so that's how it works' while I code.
So here is one:
A MultiDataTrigger trigger lets you define a set of rules that when all are true, will make updates to a user interface.
In my case, I created one that would enable the commit button of my dialog box if all the required fields had been successfully filled in and validated:
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding ElementName=textBoxWorldName, Path=Text,
Converter={StaticResource StringLengthToBooleanConverter}}" Value="true" />
<Condition Binding="{Binding ElementName=textBoxWorldAddress, Path=Text,
Converter={StaticResource StringLengthToBooleanConverter}}" Value="true" />
<Condition Binding="{Binding ElementName=textBoxWorldPort, Path=Text,
Converter={StaticResource StringLengthToBooleanConverter}}" Value="true" />
<Condition Binding="{Binding ElementName=textBoxWorldPort, Path=(Validation.HasError)}"
Value="false"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="IsEnabled"
Value="True" />
</MultiDataTrigger.Setters>
</MultiDataTrigger>
This code is correct. However, for some reason, it still wasn't working.
I puzzled over why, did some digging on the MSDN forums and discovered why.
A MultiDataTrigger can only be used inside a Style for an object. (It can't be set in Button.Triggers for example).To set the default state for the button (false until otherwise set true), I did the following:
...
<Button Content="_Start Connection"
Width="Auto"
MinHeight="24"
Margin="10,10,10,10"
MinWidth="92"
x:Name="buttonCommit"
IsEnabled="False"
IsDefault="True">
<Button.Style>
<Style TargetType="{x:Type Button}"> <Style.Triggers>
<MultiDataTrigger>
....
The IsEnabled property that I set within the Button element, overrode any change I wanted to make using the MultiDataTrigger which was located inside the style. As local set properties override Style, even if the Style is locally hosted within the element's Style property, it is an extra layer on top of the Style Override tree I mentioned in a previous post.
The fix of course, is move the setting of that property in to the Style its self, thus any Triggers have the full right to override it. As so:
...
<Button Content="_Start Connection"
Width="Auto"
MinHeight="24"
Margin="10,10,10,10"
MinWidth="92"
x:Name="buttonCommit"
IsDefault="True">
<Button.Style>
<Style TargetType="{x:Type Button}"> <Setter Property="IsEnabled"
Value="False" />
<Style.Triggers>
<MultiDataTrigger>
...
PS: If you came here and wanted information about the Converter I'm using there, let me know in a comment and I'll whip up a quick post.