Using Caliburn.Micro binding feature on an “inner” user control

此生再无相见时 提交于 2019-12-04 07:28:50

Caliburn.Micro doesn't deal well with automatically linking multiple items to a single control. However you don't have to rely on the automatic binder, you can use a plain old wpf binding instead.

A UserControl is the way to go here. In the code you can add two DependencyProperties, LabelText and Text.

Then in the XAML for your UserControl, bind to the new properties.

Where you use this control you can now set the LabelText and Text values in XAML. So on your main view add the control, and bind LabelText and Text to the properties in your ViewModel.

What you need to do is use a ContentControl in your main view to display the ConnectedSystem property of the main view model. By using a ContentControl you will get included in the view model binding process and the view model binder rules will be applied. So you want your property (using the default implementation of Caliburn) to be of type ConnectedSystemViewModel and have a view named ConnectedSystemView. Then in the view used to display the parent you want a ContentControl with an x:Name of ConnectedSystem (the name of the ConnectedSystemViewModel property. This will cause the view model binder to connect the two and do its usual work. Here is some code for clarity:

ConnectedSystemView.xaml (the user control that conventions will use when specifying ContentControl as the control to display the connected system property of main view model)

<UserControl x:Class="Sample.Views.ConnectedSystemView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>

        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>

        <Label Grid.Column="0"
                   Grid.Row="0">PropertyOne Label:</Label>
        <TextBox x:Name="PropertyOne"
                 Grid.Column="1"
                 Grid.Row="0"></TextBox>

        <TextBlock Grid.Column="0"
                   Grid.Row="1">PropertyTwo Label:</TextBlock>
        <TextBox x:Name="PropertyTwo"
                 Grid.Column="1"
                 Grid.Row="1"></TextBox>

        <!-- repeat the TextBlock, TextBox pair for the remaining
             properties three through ten -->
    </Grid>
</UserControl>

ConnectedSystemViewModel.cs (the type of the ConnectedSystem property on your main view model)

namespace Sample.ViewModels
{
    public class ConnectedSystemViewModel : PropertyChangedBase
    {
        private string _propertyOne;
        public string PropertyOne
        {
            get { return _propertyOne; }
            set
            {
                _propertyOne = value;
                NotifyOfPropertyChange(() => PropertyOne);
            }
        }

        // these all need to be as above with NotifyPropertyChange,
        // omitted for brevity.
        public string PropertyTwo { get; set;}
        public string PropertyThree { get; set;}
        public string PropertyFour { get; set;}
        public string PropertyFive { get; set;}
        public string PropertySix { get; set;}
        public string PropertySeven { get; set;}
        public string PropertyEight { get; set;}
        public string PropertyNine { get; set;}
        public string PropertyTen { get; set;}
    }
}

And in your main view define a ContentControl named relative to the main view model property of type ConnectedSystemViewModel

<ContentControl x:Name="ConnectedSystem"></ContentControl>

If I understand you question correctly this should be all you need to hook into the default Caliburn.Micro conventions. Obviously you will add the 10 ConnectedSystem properties to ConnectedSystemViewModel and appropriate controls with appropriate names to ConnectedSystemView to complete the implementation.

This way inside your main view you only need to define the one ContentControl to display the ConnectedSytem property (instead of 10 identical custom user controls) and conventions will determine the type of user control to use to fill the ContentControl.

Inside the ConnectedSystemView which will be inserted to the content property of your main views ContentControl via conventions, you have the controls you want to display your 10 connected system properties.

If you just want to display or set the property, my approach is like this:

public String ConnectedSystemName
{
    get { return _connectedSystem.Name; }
    set
    {
        _connectedSystem.Name = value;
        NotifyOfPropertyChange(() => _connectedSystem.Name);
    }
}

If you want to display or set the property from parent of user control, you can create attached property to bind to user control which is it get/set the property from user control

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!