Lindsay
Lindsay

Reputation: 595

DependencyObject is not updating the View

I have a ViewModel that is a DependencyObject for which the DependencyPropertys are not updating the View with the new values.

A sample property (the get/set wrapper is called as expected)

public static readonly DependencyProperty WeaponNameProperty = DependencyProperty.Register(
        "WeaponName",
        typeof(string),
        typeof(WeaponSystemVM),
        new PropertyMetadata(null, new PropertyChangedCallback(OnWeaponNameChanged)));
    public string WeaponName
    {
        get { return (string)GetValue(WeaponNameProperty); }
        set { SetValue(WeaponNameProperty, value); }
    }

The Callback (called when WeaponName is changed)

private static void OnWeaponNameChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    WeaponSystemVM vm = d as WeaponSystemVM;
    if (vm != null)
    { vm.CommandAddWeaponSystem.RaiseCanExecuteChanged(); }
}

The CanExecute Delegate (gets run as expected and updates the relevant Button)

private bool CanAddSystem()
{
    if (string.IsNullOrWhiteSpace(WeaponName)) return false;
    if (string.IsNullOrWhiteSpace(WeaponLock)) return false;
    if (string.IsNullOrWhiteSpace(WeaponDamage)) return false;
    if (string.IsNullOrWhiteSpace(WeaponAttack)) return false;
    return true;
}

The input TextBox

<TextBox x:Name="NameInput" Text="{Binding WeaponName, Mode=TwoWay}" Margin="12,4" RelativePanel.Below="NameAdorner" RelativePanel.AlignLeftWithPanel="True"
                     RelativePanel.AlignRightWithPanel="True"/>

The output TextBlock (is NOT updated with the new value and the DataContext is the same as the input TextBox)

<TextBlock Text="{Binding WeaponName}"/>

Frustratingly, it seems to be just this implementation that isn't working.
In an attempt to reproduce the issue, I created a seperate project without all the extra info associated with my app, and the View is being updated exactly as expected.

What I don't understand is what is not being done correctly in this implementation. The ViewModel is updating exactly as expected. The Bindings are valid according to the LiveVisualTree.
Can anyone point me to the issue?

Upvotes: 0

Views: 98

Answers (1)

Sergio
Sergio

Reputation: 2108

You shouldn't use DependencyPropertys in your ViewModel: it is a markup class, used for binding on the View side. Overkill and out of scope for it being used that way.
You should implement INotifyPropertyChanged, and fire the INotifyPropertyChanged.PropertyChanged event in every single property you want to notify the UI about.
Something like:

your ViewModel inherits from

public abstract class NotifyPropertyChangedBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
    {
        this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    protected void SetAndRaiseIfChanged<T>(
        ref T backingField,
        T newValue,
        [CallerMemberName] string propertyName = null)
    {
        if (!object.Equals(backingField, newValue))
            return;

        backingField = newValue;
        this.RaisePropertyChanged(propertyName);
    }
}

and in your ViewModel you define your property like

private string _weaponName;
public string WeaponName
{
    get { return this._weaponName; }
    set { SetAndRaiseIfChanged(ref this._weaponName, value); }
}

a more concise CanAddSystem

private bool CanAddSystem()
{
    return 
        !string.IsNullOrWhiteSpace(WeaponName)
        && !string.IsNullOrWhiteSpace(WeaponLock)
        && !string.IsNullOrWhiteSpace(WeaponDamage)
        && !string.IsNullOrWhiteSpace(WeaponAttack);
}

build your ViewModel's command with something that implements ICommand interface (something like a RelayCommand)

the View piece would be

<TextBlock Text="{Binding WeaponName}"/>

and you're done: when you bind an ICommand to the UI, the system automatically updates the CanExecute reading it from the ViewModel.

Upvotes: 2

Related Questions