1

I'm using Caliburn.Micro in my app. What I want to do is:

  • Create one RadioButton per available licence in the View
  • Check the one whose licence is currently active

So far I have two properties on my ViewModel (I'm leaving out INotify...Changed and its implementations here because that works):

BindableCollection<LicenceInfo> AvailableLicences { get; set; }
LicenceInfo ActiveLicence { get; set; }

In the ViewModel's constructor, I populate AvailableLicences and ActiveLicence. So far, so good.

Currently in the View itself, I have an ItemsControl which contains the RadioButtons and an invisible FrameworkElement to pass to MyConverter, where I extract the DataContexts of Self and the invisible FrameworkElement (whose DataContext is bound to the ViewModel) and compare them with (overridden) LicenceInfo.Equals():

<FrameworkElement Name="ActiveLicence" Visibility="Collapsed" />
<ItemsControl Name="AvailableLicences">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <RadioButton cal:Message.Attach="[Event Checked] = [Action ChangeActiveLicence($dataContext)]">
                 <RadioButton.IsChecked>
                     <MultiBinding Converter="{StaticResource MyConverter}" Mode="OneWay">
                         <Binding RelativeSource="{RelativeSource Self}" />
                         <Binding ElementName="ActiveLicence" />
                     </MultiBinding>
                 </RadioButton.IsChecked>
                 [...]

This actually works as intended, but it seems to me like an ugly workaround and I'm sure that I'm missing something.

Using <Binding x:Name="ActiveLicence" /> or <Binding Path="ActiveLicence" /> as the second parameter and removing the invisible FrameworkElement does not work, the ViewModel property is not being attached to the binding.

I'm not necessarily tied to using a MultiBinding. Anything similar to the Caliburn.Micro action like the one handling the Checked event would be welcome too. Any ideas?

Hannes
  • 273
  • 3
  • 14
  • Just having an `IsActive` flag in the `LicenceInfo` class wouldn't be an option? – Clemens Mar 14 '14 at 11:09
  • I'm afraid no, in this case it isn't. And even if it was, that wouldn't solve the actual problem. Since I'm still learning stuff, I'd be very interested in how to handle this class of issue respectively where am I wrong or what am I missing. – Hannes Mar 14 '14 at 11:19
  • You would usually have something like a ListBox (which derives from ItemsControl) that has a `SelectedItem` property and bind that to your `ActiveLicence` view model property. – Clemens Mar 14 '14 at 11:56

1 Answers1

1

From my point of view, you're pretty close to a good solution here, if adding a flag on the LicenceViewModel is not an option:

Instead of using the container framework element, try the following multi binding:

<MultiBinding Converter="{StaticResource MyConverter}" Mode="OneWay">
    <Binding Path="DataContext" RelativeSource="{RelativeSource Self}" />
    <Binding Path="DataContext.ActiveLicense" RelativeSource="{RelativeSource FindAncestor, AncestorType=ItemsControl}" />
</MultiBinding>

Modify the converter to compare two objects using Equals(), agnostic of the concrete type. That way, you're not messing around with unnecessary objects, still separating Views and ViewModels properly.

EDIT:

Regarding the alternative solution with a flag: I didn't notice, there is no LicenseViewModel involved in your code... Adding a flag to License info is not a good solution, I agree. You can consider to wrap the LicenseInfos inside LicenseInfoViewModels, though this would require a bit of infrastructure for the synchronization between the original collection of LicenseInfos on the model and the collection containing the ViewModels.

I have posted an extensive answer on that topic here.

Then you could set the flag of the active license's ViewModel to true and all others to false, when the ActiveLicense property changes.

It's a question of the specific context, whether it makes sense to go the extra mile here. If you don't plan to extend features over time etc, and it's just a simple selection of licenses, the first solution is sufficient, probably.

Community
  • 1
  • 1
Marc
  • 12,706
  • 7
  • 61
  • 97
  • I doubt the `` thing in the second binding. Shouldn't it be just ``? – Clemens Mar 14 '14 at 11:52
  • Absolutely... Edited it. – Marc Mar 14 '14 at 12:18
  • With a minor correction (`` doesn't compile, so I'm using ``), it works as expected, thanks a lot. I'd be glad to accept the answer, but you indicated that there'd be another solution if adding a flag to the LicenceViewModel would be an option. Well, it actually is an option. What I cannot do is adding a flag to the `LicenceInfo` class. – Hannes Mar 17 '14 at 07:19
  • @Hannes: I've edited my answer, maybe the new aspects help. I think you're well off with the first solution, though. – Marc Mar 17 '14 at 07:44
  • Before I asked this question, I had also considered the additional flag solution you suggest, including its benefits and drawbacks. The simplicity of the first solution makes it quite attractive and suits my needs in this particular case pretty much, so this is what I'll stick with for the time being. "Going the extra mile" can still be done in the future when requirements change. – Hannes Mar 17 '14 at 10:46