Reputation: 1050
OK, I am sure I have this setup correctly...
I have a grid, as shown here:
<Grid Grid.Row="1" Grid.Column="1" Background="{Binding CrewSelBG[1]}">
Ok. I have the following array, here:
private string[] crewSelBG;
public string[] CrewSelBG
{
get
{
return crewSelBG;
}
set
{
crewSelBG = value;
OnPropertyChanged("CrewSelBG");
}
}
I initialise the values in my array in the constructor of my viewmodel as shown here:
CrewSelBG = new string[26];
CrewSelBG = Enumerable.Repeat("#8a008a00", 26).ToArray();
This initialises the entire array to a green colour. (In fact the green colour should actually be #00000000 but I wanted to see it was bound correctly). I have a checkbox, which when clicked activates an icommand. Here is my checkbox:
<CheckBox Grid.Column="0" IsChecked="{Binding CrewChecked[1]}" Margin="5,0,0,0" Command="{Binding CrewSelectCheck}" CommandParameter="01"/>
And the ICommand it calls is setup here:
private ICommand crewSelectCheck;
public ICommand CrewSelectCheck
{
get
{
if (crewSelectCheck == null)
{
crewSelectCheck = new RelayCommand(param => this.CrewSelectCheckEx(param.ToString()), null);
}
return crewSelectCheck;
}
}
public void CrewSelectCheckEx(string p)
{
if (CrewChecked[Convert.ToInt32(p)])
{
CrewSelBG[Convert.ToInt32(p)] = "AliceBlue";//selected
}
else
{
CrewSelBG[Convert.ToInt32(p)] = "#00000000";
}
}
OK... So... When clicking the checkbox and its moving to a checked state, it triggers the line setting CrewSelBG[1] to AliceBlue. I put a breakpoint on this line and it does indeed trigger the line. I stepped one more line of code, and CrewSelBG[1] did indeed, change to "AliceBlue". The background of my grid however stays green, (or whatever value I put in the constructor).
I dont understand why it won't update??? I have an onpropertyraised event for it (I tried adding the following as well, which didn't work:
OnPropertyChanged("CrewSelBG[1]");
That did nothing either.)
Any ideas?
Upvotes: 0
Views: 763
Reputation: 67380
OK let's do some WPF 101.
What you actually wrote, that property for CrewSelBG
, it only triggers the WPF update mechanism if you replace the entire array object. That's why it picks up the initial color, because you create an entirely new array and assign it through the property setter. Of course you do that twice back to back for some reason, but that's job insurance probably, something to 'fix' later so you still seem useful.
Now, just because you write CrewSelBG[Convert.ToInt32(p)] = "AliceBlue";
that doesn't mean WPF will pick it up. How could it, you use the getter of that property (no notify) and replace an item in some array somewhere.
WPF actually provided you with an easy to use replacement, simply use ObservableCollection<>
. What it does is it provides its own this[]
indexer, and in that indexer's setter it notifies WPF it changed. It's perfect!
It is however not magic -- you can easily write that yourself. Instead of the INotifyPropertyChanged
interface, which only has one notifier for the entire sequence, you can use INotifyCollectionChanged
which provides an indexed notifier so you can tell WPF only an index from your collection has changed.
And just to get it out of the way, you have a lot of "I added ... in my code" and "I tried ... and didn't work" in your post and comments, which leads me to believe you type random lines at random. ObservableCollection<>
will work. You just have to ensure the proper DataContext
is set, in addition to your binding. If you go the INotifyCollectionChanged
route, you also have to make sure you notify from the proper context in the first place -- ie you won't put it in your CrewSelectCheckEx
function.
Upvotes: 0
Reputation: 69959
The problem is that you are changing a value from your CrewSelBG
array, rather than changing the array. Therefore, your OnPropertyChanged
method is not being called and the UI is not notified of the change. To fix this, just manually call your OnPropertyChanged
method when you change the value, like this:
public void CrewSelectCheckEx(string p)
{
if (CrewChecked[Convert.ToInt32(p)])
{
CrewSelBG[Convert.ToInt32(p)] = "AliceBlue";//selected
}
else
{
CrewSelBG[Convert.ToInt32(p)] = "#00000000";
}
OnPropertyChanged("CrewSelBG");
}
Upvotes: 0
Reputation: 2204
This is where an ObservableCollection
is preferable. You should be able to change string[]
to ObservableCollection<string>
and have it work correctly.
You can also try OnPropertyChanged("CrewSelBG")
but even if it works it will invalidate all of your bindings to its elelements.
Upvotes: 1