Coder Social home page Coder Social logo

Comments (8)

nedmech avatar nedmech commented on September 15, 2024

I haven't used this library directly, but looked at parts of it as inspiration to roll my own. Looking at the source code and unit tests for this library, I'm pretty sure you need to call SetProperty in your property setters to get them to broadcast a PropertyChanged event that would trigger your handler that calls the RaiseCanExecuteChanged method. Also, does your Airport class also implement BaseViewModel/INotifyPropertyChanged? The Airport.name property (or is it just a field?) would need to emit a PropertyChanged event as well, and I think you'd have to set-up/tear-down a weak-event-listener to listen for the SelectedItem.name change as the SelectedItem changes.

Instead, I might suggest wrapping the SelectedItem.name in a SelectedItemName property to make the event handling easier:

private Airport? _selectedItem;
public Airport? SelectedItem
{
    get => _selectedItem;
    set
    {
        SetProperty(ref _selectedItem, value);
        // Broadcast that the SelectedItemName should now have a new value as well.
        OnPropertyChanged(nameof(SelectedItemName);
        // Broadcast that the command's CanExecute should be re-evaluated now.
        MyProperty.RaiseCanExecuteChanged();
    }
}

SelectedItemName // Bind this to your TextBox.Text instead
{
    get => SelectedItem?.name ?? string.Empty;
    set
    {
        if (null == SelectedItem)
        {
            // Can't set the value if no item is selected.
            // Broadcast the changed event to refresh the binding (will be empty string).
            // This effectively rejects typing in the box until an item is selected.
            OnPropertyChanged();
            return;
        }
        SetProperty(ref SelectedItem.name, value); // Note: this may only work if Airport.name is a field, not a property.
        /* If Airport.name is a property, do this instead:
        SelectedItem.name = value;
        OnPropertyChanged(); // Broadcast that this property (SelectedItemName) has a new value.
        */
        // Broadcast that the command's CanExecute should be re-evaluated now.
        MyProperty.RaiseCanExecuteChanged();
    }

This way you can drop the anonymous PropertyChanged event delegate from your constructor altogether.

Also, you probably don't need the public setters for your MyProperty, Services, or AirportsList properties - typically nothing outside of this class should probably be setting those.

You might want to add UpdateSourceTrigger=PropertyChanged to your TextBox.Text binding as well so it updates as you type instead of the default behavior of only updating after the focus changes (unless that's the behavior you want).

Hope this helps, and if it's still having an issue, maybe there really is an issue with the library. Although I suspect this should address your problem.

from mvvm-helpers.

eduardoagr avatar eduardoagr commented on September 15, 2024

Thanks, @nedmech, I have a question, if I am using fody to inject my property change, Do I still need

private Airport? _selectedItem;
public Airport? SelectedItem
{
    get => _selectedItem;
    set
    {
        SetProperty(ref _selectedItem, value);
        // Broadcast that the SelectedItemName should now have a new value as well.
        OnPropertyChanged(nameof(SelectedItemName);
        // Broadcast that the command's CanExecute should be re-evaluated now.
        MyProperty.RaiseCanExecuteChanged();
    }
}

As far as I know, when you add fody and put in your class [addNotifyPropertyChangeInterface] it will add all that code for you you only need to do is

public Airport SelectedItem { get; set }

Also my class has the [AdNotyfyProertyChangeAtribute] courtesy of fody

from mvvm-helpers.

nedmech avatar nedmech commented on September 15, 2024

I haven't used fody before, so I'm not familiar with the usage. A quick peek at it seems like you're probably correct - it should be auto-generating the code for notifying that the selected item has changed. Although there's still the question of whether or not the Airport.name is a field or property and if the Airport class implements INotifyPropertyChanged. Even if your Airport.name is a notifying property, there's still a missing connection between the SelectedItem.name changing and triggering the RaiseCanExecuteChanged. Without a weak-event-listener or wrapping it in another property, there's nothing in your MainWindowViewModel that is listening for change notifications from the Airport.name value.

Try it with just the SelectedItemName property wrapper and see what happens. My guess is that typing in a name will trigger the CanExecute update, but just selecting an item won't. Maybe some combination of my idea and your original code where you subscribed to the PropertyChanged event will work since you should get the PropertyChanged event when the SelectedItem changes and when the SelectedItemName is updated. You can probably exclude the RaiseCanExecuteChanged from the SelectedItemName setter in this case.

from mvvm-helpers.

eduardoagr avatar eduardoagr commented on September 15, 2024

I did it, but there is a small issue

the button only enables, when I press the tab, to make it loses focus, what I want to do is that when I type the button enables infinitely, without me having to change the control focus or anything like that.

I just my code in GitHub, if you want to check it out or modify it or whatever

https://github.com/eduardoagr/Travel

By the way, this library in combination with fody is extraordinary

from mvvm-helpers.

nedmech avatar nedmech commented on September 15, 2024

To get the changes to register immediately when typing in the TextBox, you need to add the UpdateSourceTrigger attribute I mentioned before to the TextBox.Text binding:

<TextBox Grid.Column="1" Text="{Binding Path=SelectedItem.name, UpdateSourceTrigger=PropertyChanged}"/>

This should cause the PropertyChanged event for the name property to fire with every keystroke.

Does the button enabled when you select an Airport item that already has a name? You may still need to add a RaiseCanExectuteChanged to the setter for the SelectedItem, or another PropertyChanged event delegate to handle refreshing the CanExecute status on selection change.

In your constructor, I think you've got a problem with the OnAnyPropertiesChanged action assignment:

        SelectedItem = new Airport
        {
            OnAnyPropertiesChanged = () => { MyProperty?.RaiseCanExecuteChanged(); }
        };

I think this will only attach to the new instance of Airport that gets created in the constructor. If you've got your AirportList and SelectedItem bound to a selectable control (ListBox, ListView, ComboBox, etc.) when you actually select a new Airport from your collection, the SelectedItem will be replaced by the selection, and that newly selected item doesn't look like it will have the OnAnyPropertiesChanged action assigned. It doesn't look like your code is completed to that point yet, but just something to be aware of.

But it sounds like you're on the right track and that there's not an issue with the library, just some tweaks needed to your implementation.

from mvvm-helpers.

eduardoagr avatar eduardoagr commented on September 15, 2024

I changed my code, but I still cannot manage to enable it as I type

from mvvm-helpers.

nedmech avatar nedmech commented on September 15, 2024

It looks like you added the UpdateSourceTrigger attribute to the Button.Command binding. It belongs on the TextBox.Text binding.

from mvvm-helpers.

eduardoagr avatar eduardoagr commented on September 15, 2024

lol, thanks so much

from mvvm-helpers.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.