1

I have an ItemsControl like the following

<ItemsControl ItemsSource="{Binding MyClass.Links}"  >
<ItemsControl.ItemTemplate>
    <DataTemplate>
        <Grid d:DesignWidth="450" d:DesignHeight="245" Height="Auto" Width="Auto">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" MinWidth="145"/>
                <ColumnDefinition Width="Auto" MinWidth="179"/>
            </Grid.ColumnDefinitions>
            <HyperlinkButton Content="{Binding ViewName}" IsEnabled="{Binding ViewEnabled, Mode=OneWay}" cmd:Click.Command="{Binding DataSource.ViewCommand, Source={StaticResource DataContextProxy}}" cmd:Click.CommandParameter="{Binding}" Margin="4"/>
        </Grid>
    </DataTemplate>
</ItemsControl.ItemTemplate>

I have an ObservableCollection of the following class that the itemssource is getting bound to

public class LinkClass : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public string ViewName { get; set; }
    private bool _viewEnabled;
    public bool ViewEnabled { 
    get { return this._viewEnabled; }
        set
        {
            if (value != this._viewEnabled)
            {
                this._viewEnabled = value;
                if (this.PropertyChanged != null)
                {
                    Deployment.Current.Dispatcher.BeginInvoke(() =>
                          this.PropertyChanged(this, new PropertyChangedEventArgs("ViewEnabled"))
                        );
                }
            }
        }
    }
}

When the command is hit in the view model, the bound link's ViewEnabled is getting set to false (disable link for view I'm looking at). The problem is, the link isn't actually getting disabled (IsEnabled set to false).

So the end question is, why isn't this working? I'm new to MVVM and silverlight, so I'm hoping it's something simple.

UPDATE

I'm setting the ViewEnabled property to true for all but the clicked button's bound LinkClass, which I'm setting to false. It is firing the PropertyChanged event for each (that changes), but not updating the UI. I ran an empty converter with the binding and it isn't getting hit either when the link is clicked, so the PropertyChanged isn't bubbling properly (or as I suspect it should anyway).

Here's the code setting the ViewEnabled properties of my collection of LinkClass:

public ICommand ViewCommand
    {
        get {
            return new DelegateCommand<object>(param =>
                {
                    this.ViewSelected((LinkClass)param);
                }); 
        }
    }

    public void ViewSelected(LinkClass link)
    {
                foreach (var containerLink in _myClass.Links)
                {
                    if (containerLink == link)
                        containerLink.ViewEnabled = false;
                    else
                        containerLink.ViewEnabled = true;
                }
        ...other code here
    }
DougJones
  • 774
  • 1
  • 9
  • 26

3 Answers3

1

Well it might actually be getting disabled but if your ViewCommand isn't paying attention to that property then you're stuck. Especially since it looks like that command is an attached property.

Googling got me this post that you might want to look at.

But personally I would look at your CanExecute of your ViewCommand and make sure that it is only running if ViewEnabled == true

Community
  • 1
  • 1
Jose
  • 10,891
  • 19
  • 67
  • 89
  • Well when I make the binding 2 way, it actually disables all links. The first pass seems correct, then the 2nd disables all of them. I know from that the functionality when it is disabled. When it is,my ViewCommand method doesn't run. – DougJones Apr 23 '11 at 16:57
  • Thanks for the help. You definitely pointed me in the right direction. – DougJones Apr 23 '11 at 23:26
0

When I was using MVVM, in the setter of my properties I had a method named NotifyPropertyChanged() and would call it passing the string value for the property's name. I'm not sure what Deployment.Current.Dispatcher.BeginInvoke(...) does, but this method always worked for me.

    public event PropertyChangedEventHandler PropertyChanged;
    public void NotifyPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;

        if (handler.IsNotNull())
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

So in my property I would do something like...

    public Nullable<int> UpdatedBy
    {
        get { return _updatedBy; }
        set
        {
            if (_updatedBy.IsEqualTo(value))
                return;

            _updatedBy = value;
            NotifyPropertyChanged("UpdatedBy");
        }
    }

Also, just grasping at straws, but try putting {Binding Path=ViewEnabled, ...} Hope this helps.

jhorton
  • 1,019
  • 3
  • 17
  • 36
  • In your example you're setting handler to PropertyChanged, then calling it the same way. The Dispatcher.BeginInvoke was to force it to run on the UI thread, which prevented an error I was receiving. I added the explicit path in the binding, but to no avail. Thanks for the help though! – DougJones Apr 21 '11 at 22:18
  • So my next question is, when are you setting it to false? Do you have it being set to false on instantiation? Try doing... private bool _viewEnabled = false; Sorry I'm not much help on this. Seems like a simple issue that shouldn't be an issue. Looks right to me. Also, I'm not familiar with the cmd:Click.Command and cmd:Click.Parameter, but is there any chance that passing the binding could be hosing up the IsEnabled binding? – jhorton Apr 22 '11 at 12:54
  • I added the code where I'm setting the ViewEnabled properties. – DougJones Apr 23 '11 at 16:54
0

Taking Jose's advice, I looked at the canExecute method of the ViewCommand (DelegateCommand) I was using, but implementing the method didn't solve the problem, as it only was run once, and not when changed. I found an example recommending to use the PropertyChanged event handler of the INotifyPropertyChanged class to call the RaiseCanExecuteChanged() method of the DelegateCommand. I did this for all of the LinkClass instances, as shown here for 1 before setting it to _myClass.Links:

var link = new LinkClass()
                             {
                                 ...
                                 ViewEnabled = true
                             };
                            link.PropertyChanged += new PropertyChangedEventHandler(link_PropertyChanged);
                            return link;

I did this, but to no avail. I then found this blog post:DelegateCommand in Prism loses eventhandler and CanExecute never gets called I then switched from Prism to a RelayCommand class and it worked! Hopefully this helps someone else out.

UPDATE

The actual issue was in using Prism's cmd:Click.Command and cmd:Click.CommandParameter in xaml. Switching from that to Command and CommandParameter properties in xaml, as I did after switching to the RelayCommand, is what actually got it working.

DougJones
  • 774
  • 1
  • 9
  • 26