0

I have a case where say I have one property that has a string which contains a separator (e.g. ':'). I have 3 text boxes and I would like to share each separated part value in each textbox and also update them when one of the textboxes value changes. How can I implement this behavior in WPF using data binding?

My case involves using Prism and MVVM, my approach is as follows:

  • Model class which inherits from bindable base
  • View model will also inherits from bindable base
  • Model instance will be created in the view model's constructor and be used as DataContext where it is needed

See this sample code here:

In my model class:

private string _someValue = "A:B:C";

public string SomeValue
{
    get => _someValue;
    set => SetProperty(ref _someValue, value);
}
5
  • 3
    Create three properties, one for each part, with setters that also fire PropertyChanged for SomeValue. Make SomeValue readonly and return the combination like public string SomeValue => $"{SomeValuePartA}:{SomeValuePartB}:{SomeValuePartC}"; Commented Oct 24 at 12:50
  • @Clemens so for SomeValue => $"{SomeValuePartA}:{SomeValuePartB}:{SomeValuePartC}"; this will be in the set property of the SomeValue? like this ` set => SetProperty(ref $"{SomeValuePartA}:{SomeValuePartB}:{SomeValuePartC}", value);` Commented Oct 24 at 13:18
  • 1
    No, SomeValue is a calculated property and should be read-only, thus not setter. Commented Oct 24 at 13:32
  • SomeValue could have a setter, though, if needed, that does the splitting and updates the other three properties. Commented Oct 24 at 14:13
  • private string _someValue = "A:B:C"; private string[] _someTokens => _someValue.Split( new char[] { ':' } ); public string SomeValuePart1 => _someTokens[ 0 ]; public string SomeValuePart2 => _someTokens[ 1 ]; public string SomeValuePart3 => _someTokens[ 2 ]; Commented Oct 24 at 15:41

2 Answers 2

4

I would use a string array as backing field for the compound value:

private string[] _parts = ["A", "B", "C"]; // if < C#12, use {"A", "B", "C"}
public string SomeValue
{
    get => String.Join(":", _parts);
    set {
        // Make sure we always have 3 parts
        _parts = (value + "::").Split(':', 3);
        OnPropertyChanged(nameof(SomeValue));
        OnPropertyChanged(nameof(A));
        OnPropertyChanged(nameof(B));
        OnPropertyChanged(nameof(C));
    }
}

public string A
{
    get => _parts[0];
    set {
        if (value != _parts[0]) {
            _parts[0] = value;
            OnPropertyChanged(nameof(A));
            OnPropertyChanged(nameof(SomeValue));
        }
    }
}

public string B
{
    get => _parts[1];
    set {

        if (value != _parts[1]) {
            _parts[1] = value;
            OnPropertyChanged(nameof(B));
            OnPropertyChanged(nameof(SomeValue));
        }
    }
}

public string C
{
    get => _parts[2];
    set {
        if (value != _parts[2]) {
            _parts[2] = value;
            OnPropertyChanged(nameof(C));
            OnPropertyChanged(nameof(SomeValue));
        }
    }
}

We must take care to notify all affected properties, so that the corresponding bound text boxes do update automatically.

Sign up to request clarification or add additional context in comments.

1 Comment

I'm actually involved in a project that takes the pain out of this exact situation. Future.UX it's on Nuget, and all you'd need is the 3 parts marked as private fields and the computed property. Have a quick look: nuget.org/packages/Future.UX.SourceGenerators
3

Create 3 additional properties for the 3 parts that also fire the PropertyChanged notification for SomeValue, like

private string someValuePartA = "A";
public string SomeValuePartA
{
    get => someValuePartA;
    set
    {
        SetProperty(ref someValuePartA, value);
        OnPropertyChanged(nameof(SomeValue));
    }
}
// equivalent for SomeValuePartB and SomeValuePartC

Declare SomeValue as readonly property that combines the 3 parts:

public string SomeValue => $"{SomeValuePartA}:{SomeValuePartB}:{SomeValuePartC}";

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.