AvaloniaUI StyledProperty and MVVM binding doesn't update

Viewed 566

I'm using AvaloniaUI and making a UserControl with a StyledProperty using. I'm using MVVM. The problem is that when I have a Binding to my styledproperty but it doesn't update.

I want to use the UserControl like this <Comp:ValueTextBlock VariableName="{Binding RobotSettingsModel.Robot_SP}"/> where VariableName uses a binding to a model that is created in the ViewModel.

The problem is that I can't seem to get the StyledProperty to work when I use a binding. When I set VariableName directly in the view it does work

// this works
<Comp:ValueTextBlock  VariableName="PLC_U1_Robot_SP"/> 
// this doesn't
<Comp:ValueTextBlock  VariableName="{Binding RobotSettingsModel.Robot_SP}" DescriptionLocation="Left"/>

What am I doing wrong here?

The code-behind for my UserControl ValueTextBlock looks something like this:

public class ValueTextBlock : UserControl
{
    private ValueTextBlockVm _viewModel;

    #region   ---   Variable name properties   ---
    public static readonly StyledProperty<string> VariableNameProperty = AvaloniaProperty.Register<ValueTextBlock, string>(nameof(VariableName), defaultBindingMode: BindingMode.TwoWay, defaultValue: "UNKNOWN DProperty");
    public string VariableName
    {
        get { return _viewModel.vmVariableName; }  // the property is used in the ViewModel
        set { _viewModel.vmVariableName = value; }
    }
    #endregion

    #region constructor
    public ValueTextBlock()
    {
        this.InitializeComponent();

        // create new instance of viewmodel and attach it as DataContext
        _viewModel = new ValueTextBlockVm();
        this.DataContext = _viewModel;
    }

    private void InitializeComponent()
    {
        AvaloniaXamlLoader.Load(this);
    }
    #endregion
}

In the ViewModel for ValueTextBlock vmVariableName is done like this:

private string _vmVariableName = "UKN";
public string vmVariableName
{
    get => _vmVariableName;
    set => this.RaiseAndSetIfChanged(ref _vmVariableName, value);
}

When i use this UserControl and directly set VariableName in view it works, but when I use Binding it doesn't work. This is my view:

<StackPanel>
  <Comp:ValueTextBlock  VariableName="PLC_U1_Robot_SP"/> <!-- directly setting VariableName works -->
  <Comp:ValueTextBlock  VariableName="{Binding RobotSettingsModel.Robot_SP}" DescriptionLocation="Left"/> <!-- binding VariableName to a model doesn't work -->
  <TextBlock Text="{Binding RobotSettingsModel.Robot_SP}"/> <!-- binding normal text to a model does work-->
</StackPanel>

Code-behind for the view

public class ucRobotSettings : UserControl
{
    private ucRobotSettingsVm _viewModel;

    #region properties
    public string Prefix
    {
        get { return _viewModel.vmPrefix; }
        set { _viewModel.vmPrefix = value; }
    }
    public static readonly StyledProperty<string> PrefixProperty = AvaloniaProperty.Register<ucRobotSettings, string>(nameof(Prefix));
    #endregion

    #region constructor
    public ucRobotSettings()
    {
        this.InitializeComponent();
        // create new instance of viewmodel and attach it as DataContext
        _viewModel = new ucRobotSettingsVm();
        this.DataContext = _viewModel;

        this.AttachedToVisualTree += ucRobotSettings_AttachedToVisualTree;
    }

    private void InitializeComponent()
    {
        AvaloniaXamlLoader.Load(this);
    }
    #endregion

    private void ucRobotSettings_AttachedToVisualTree(object sender, VisualTreeAttachmentEventArgs e)
    {
        _viewModel.OnAttachedToVisualTree();
    }
}

In the ViewModel a new RobotSettingsModel is made, this is what I want to bind to in the View

public class ucRobotSettingsVm : ViewModelBase
{
    #region   ---   properties   ---
    private string _vmPrefix;
    public string vmPrefix
    {
        get => _vmPrefix;
        set => this.RaiseAndSetIfChanged(ref _vmPrefix, value);
    }

    private RobotSettingsModel _RobotSettingsModel = new RobotSettingsModel();
    public RobotSettingsModel RobotSettingsModel
    {
        get => _RobotSettingsModel;
        set => this.RaiseAndSetIfChanged(ref _RobotSettingsModel, value);
    }
    #endregion

    public ucRobotSettingsVm() { }

    public void OnAttachedToVisualTree()
    {
        // don't update if the prefix hasn't changed
        if (RobotSettingsModel.Prefix != vmPrefix) RobotSettingsModel.Prefix = vmPrefix;
    }
}

The model that is used in ucRobotSettings looks like this:

public class RobotSettingsModel : ReactiveObject
{
    // unit prefix.
    private string _Prefix;
    public string Prefix { get => _Prefix; set { this.RaiseAndSetIfChanged(ref _Prefix, value); NotifyPropertyChanged(); } }

    // values
    private string _Robot_SP = "UKN";
    public string Robot_SP { get => _Robot_SP; set => this.RaiseAndSetIfChanged(ref _Robot_SP, value); }

    public RobotSettingsModel()
    { }

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] String propertyName = "")
    {
        if (propertyName == "Prefix") // only update when property "Prefix changes"
        {
            Robot_SP = Prefix + "_" + nameof(Robot_SP);

            // inform outside outside world the complete class has PropertyChanged
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
0 Answers
Related