Caliburn.Micro icon indicating copy to clipboard operation
Caliburn.Micro copied to clipboard

Custom usage of ViewModelBinder.Bind(object, dependencyObject, object) not using conventions.

Open dealproc opened this issue 11 years ago • 23 comments

My assumption here is that I am doing something wrong, but need to ask the group and get a feedback that I can move forward with.

I am using MahApps Metro for a UI control suite, and Caliburn Micro to orchestrate the interaction of screens.

I have the following to show a custom dialog:

public IEnumerable<IResult> Handle(AggEvents.ShowDialog message) {
    var screen = _LifetimeScope.Resolve(message.View);
    if (screen != null) {
        var view = ViewLocator.LocateForModel(screen, null, null) as BaseMetroDialog;
        ViewModelBinder.Bind(screen, view, null);

        var activator = screen as IActivate;

        if (activator != null) {
            activator.Activate();
        }

        yield return Window.ShowMetroDialogAsync(view).AsResult();
    }
}

What is happening is that if I do not call cal:Message.Attach="Ok()" on my buttons, the commands are not binding appropriately on screen.

I honestly feel as if I'm not doing something appropriately (and yes, I did x:Name="Ok" for the Ok button, for example) already.

Anyone with any help/advice on what I may have made a mistake on above... the help would be greatly appreciated.

dealproc avatar Nov 03 '14 21:11 dealproc

I can't see anything obviously wrong with that code, do any of the CM conventions work inside that view or is it just the buttons that aren't having conventions applied?

nigel-sampson avatar Nov 03 '14 21:11 nigel-sampson

I'm just getting into building the view out, and adopting other values from the ViewModel. Let me see what happens as I continue.

dealproc avatar Nov 03 '14 21:11 dealproc

It's looking like it's the button click events that are not binding unless I use the cal:Message.Attach method to bind out. Properties seem to be bound appropriately.

dealproc avatar Nov 03 '14 21:11 dealproc

Can I confirm the buttons are located in the view?

It sounds a silly question, but often there's a content control representing the dialog that ends up containing the view and the buttons. If that's the case then the buttons won't have the conventions applied.

nigel-sampson avatar Nov 03 '14 21:11 nigel-sampson

Verbatim from screen:

<mahappsDialog:SimpleDialog x:Class="BTRG.DMF.GUI.Views.RunningProjectsView"
                            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                            xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                            xmlns:mahappsDialog="clr-namespace:MahApps.Metro.Controls.Dialogs;assembly=MahApps.Metro"
                            xmlns:cal="http://www.caliburnproject.org"
                            mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="650">
    <Grid MinHeight="400">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <TextBlock Text="{Binding Title}" HorizontalAlignment="Center" VerticalAlignment="Center" />
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Grid.Row="1">
            <Button Style="{StaticResource GreenButton}" Content="Ok" cal:Message.Attach="Ok()" />
            <Button Style="{StaticResource BlueButton}" Content="Cancel" cal:Message.Attach="Cancel()" />
        </StackPanel>
    </Grid>
</mahappsDialog:SimpleDialog>

dealproc avatar Nov 03 '14 21:11 dealproc

If you set the x:Name of the TextBlock to Title (and remove the binding) is the convention being applied?

nigel-sampson avatar Nov 03 '14 21:11 nigel-sampson

Namespace issues?

mvermef avatar Nov 03 '14 21:11 mvermef

It is not. I have never done that before, and hadn't realized that the labels had shared a similar convention to the buttons.

dealproc avatar Nov 03 '14 21:11 dealproc

Can you add the following to your bootstrapper to enable logging for the view model binder.

var baseGetLog = LogManager.GetLog;

LogManager.GetLog = t => t == typeof (ViewModelBinder) ? new DebugLog(t) : baseGetLog(t);

You can view the output in your debug log.

nigel-sampson avatar Nov 03 '14 21:11 nigel-sampson

Ok... but what does this mean? Do I need to embed the controls within something specific under the base metro dialog control in order to provide the right hierarchy for the controls?

[Caliburn.Micro.ViewModelBinder] INFO: Binding BTRG.DMF.GUI.Views.RunningProjectsView and BTRG.DMF.GUI.ViewModels.RunningProjectsViewModel.
[Caliburn.Micro.ViewModelBinder] INFO: Attaching BTRG.DMF.GUI.Views.RunningProjectsView to BTRG.DMF.GUI.ViewModels.RunningProjectsViewModel.
[Caliburn.Micro.ViewModelBinder] INFO: Action Convention Not Applied: No actionable element for get_Title.
[Caliburn.Micro.ViewModelBinder] INFO: Action Convention Not Applied: No actionable element for set_Title.
[Caliburn.Micro.ViewModelBinder] INFO: Action Convention Not Applied: No actionable element for Ok.
[Caliburn.Micro.ViewModelBinder] INFO: Action Convention Not Applied: No actionable element for Cancel.
[Caliburn.Micro.ViewModelBinder] INFO: Action Convention Not Applied: No actionable element for get_Parent.
[Caliburn.Micro.ViewModelBinder] INFO: Action Convention Not Applied: No actionable element for set_Parent.
[Caliburn.Micro.ViewModelBinder] INFO: Action Convention Not Applied: No actionable element for get_DisplayName.
[Caliburn.Micro.ViewModelBinder] INFO: Action Convention Not Applied: No actionable element for set_DisplayName.
[Caliburn.Micro.ViewModelBinder] INFO: Action Convention Not Applied: No actionable element for get_IsActive.
[Caliburn.Micro.ViewModelBinder] INFO: Action Convention Not Applied: No actionable element for get_IsInitialized.
[Caliburn.Micro.ViewModelBinder] INFO: Action Convention Not Applied: No actionable element for add_Activated.
[Caliburn.Micro.ViewModelBinder] INFO: Action Convention Not Applied: No actionable element for remove_Activated.
[Caliburn.Micro.ViewModelBinder] INFO: Action Convention Not Applied: No actionable element for add_AttemptingDeactivation.
[Caliburn.Micro.ViewModelBinder] INFO: Action Convention Not Applied: No actionable element for remove_AttemptingDeactivation.
[Caliburn.Micro.ViewModelBinder] INFO: Action Convention Not Applied: No actionable element for add_Deactivated.
[Caliburn.Micro.ViewModelBinder] INFO: Action Convention Not Applied: No actionable element for remove_Deactivated.
[Caliburn.Micro.ViewModelBinder] INFO: Action Convention Not Applied: No actionable element for CanClose.
[Caliburn.Micro.ViewModelBinder] INFO: Action Convention Not Applied: No actionable element for TryClose.
[Caliburn.Micro.ViewModelBinder] INFO: Action Convention Not Applied: No actionable element for add_ViewAttached.
[Caliburn.Micro.ViewModelBinder] INFO: Action Convention Not Applied: No actionable element for remove_ViewAttached.
[Caliburn.Micro.ViewModelBinder] INFO: Action Convention Not Applied: No actionable element for GetView.
[Caliburn.Micro.ViewModelBinder] INFO: Action Convention Not Applied: No actionable element for add_PropertyChanged.
[Caliburn.Micro.ViewModelBinder] INFO: Action Convention Not Applied: No actionable element for remove_PropertyChanged.
[Caliburn.Micro.ViewModelBinder] INFO: Action Convention Not Applied: No actionable element for get_IsNotifying.
[Caliburn.Micro.ViewModelBinder] INFO: Action Convention Not Applied: No actionable element for set_IsNotifying.
[Caliburn.Micro.ViewModelBinder] INFO: Action Convention Not Applied: No actionable element for Refresh.
[Caliburn.Micro.ViewModelBinder] INFO: Action Convention Not Applied: No actionable element for NotifyOfPropertyChange.
[Caliburn.Micro.ViewModelBinder] INFO: Action Convention Not Applied: No actionable element for NotifyOfPropertyChange.
[Caliburn.Micro.ViewModelBinder] INFO: Action Convention Not Applied: No actionable element for ToString.
[Caliburn.Micro.ViewModelBinder] INFO: Action Convention Not Applied: No actionable element for Equals.
[Caliburn.Micro.ViewModelBinder] INFO: Action Convention Not Applied: No actionable element for GetHashCode.
[Caliburn.Micro.ViewModelBinder] INFO: Action Convention Not Applied: No actionable element for GetType.

dealproc avatar Nov 03 '14 22:11 dealproc

was there anything else near the bottom of the output for that dialog?

mvermef avatar Nov 03 '14 22:11 mvermef

This seems to work.

public IEnumerable<IResult> Handle(AggEvents.ShowDialog message) {
    var screen = _LifetimeScope.Resolve(message.View);
    if (screen != null) {
        var view = ViewLocator.LocateForModel(screen, null, null) as BaseMetroDialog;

        yield return Window.ShowMetroDialogAsync(view).AsResult();
        yield return Task.Factory.StartNew(() => {
            ViewModelBinder.Bind(screen, view, null);

            var activator = screen as IActivate;

            if (activator != null) {
                activator.Activate();
            }
        }).AsResult();
    }
}

This leads me to believe that the UI bits need to be created and shown before the binder can do its job onscreen... am I correct on this?

dealproc avatar Nov 03 '14 22:11 dealproc

did the x:Name="Title" get set on the textblock instead of the Text="{Binding Title}", I think what Nigel was looking for was whether or not the ViewModelBinder was actually finding the controls in question. That is why he asked if you could set x:Name="Title" on that textblock, because the DebugLog output would be slightly different.

mvermef avatar Nov 03 '14 22:11 mvermef

Yes, once I rolled over to this new way of building the code, all the x:name="..." works as expected. Now I'm just trying to understand the "why" of it.

dealproc avatar Nov 03 '14 22:11 dealproc

late binding?

mvermef avatar Nov 03 '14 22:11 mvermef

Most of the time there's no problem creating the UI bits and binding them before showing them on screen. However it does appear that this is the problem there. Until the dialog is displayed it's not finding the named elements to display.

As a test can you call

 var namedElements = BindingScope.GetNamedElements(element);

before the ViewModelBinder.Bind(screen, view, null); in both the working and not working code and compare the results?

nigel-sampson avatar Nov 03 '14 22:11 nigel-sampson

I think, at this point, we'll call well-enough alone :)

Thanks for being a sounding board @nigel-sampson!

dealproc avatar Nov 03 '14 22:11 dealproc

working code - 74 elements. non-working code - 0 elements.

dealproc avatar Nov 04 '14 17:11 dealproc

It's not making sense. all of my x:Name="" are working as expected, my <TextBlock Text="{Binding ...}" /> stuff is working as expected too... but if you need any detail records, it doesn't seem to be inheriting the proper view scope. (e.g. do a binding to an ItemsSource and try to link the data context's button to a code-behind click event).

Is there a trick in the code base to find out what the button's context is, and how to resolve to get it to point to the right area? There are other controls in this same area that are getting their binding much like the above textblock.

Apologies if this sounds cross, just becoming a pain to try to deal with this particular way of binding up. completely lost.

dealproc avatar Nov 04 '14 21:11 dealproc

Sorry I don't follow what you mean by "do a binding to an ItemsSource and try to link the data context's button to a code-behind click event".

nigel-sampson avatar Nov 04 '14 21:11 nigel-sampson

master... detail view models. I think ultimately, i'm building the dialog wrong. in the MahApps Metro project, someone offered a solution for running dialogs. Unfortunately, i'm under the gun (8 hours left in project), but I think i have to refactor to it.

Let me try that in the morning, and I'll get back to you.

dealproc avatar Nov 04 '14 23:11 dealproc

crap. i didn't realize i left this open... i need to review this, at some point, and see if it's resolved.

dealproc avatar Apr 30 '15 03:04 dealproc

Don't think anything here has been resolved. I've left it open to come back to when I have time.

nigel-sampson avatar May 03 '15 21:05 nigel-sampson