0

I'm writing a uwp program, where I want to bind a ObservableCollection to visibility of an Ellipse in a Ellipse matrix. Since I want to make the number of ellipses flexible, I initialize and bind them in the c# initialization code of the page. The problem is the ellipses' visibilities reflect the bool values which I set before the binding happens, but when the bool value changes after binding, the visibilities don't change with the bool value's change.

I declare the bool values in the App.xaml.cs

public int gameRow;`enter code here`
public int gameColumn;
public ObservableCollection<bool> gameMatrix;

In the page of ellipses, I declare a Grid to hold the ellipses in the GamePage.xaml.

<Grid Grid.Column="1" Grid.Row="0"  x:Name="gameFlat"/>

In the corresponding GamePage.xaml.cs, I initialized ellipses, bind them to the bool values, and put them in a row/column in the gameFlat grid.

private void addEllipse(int i, int j, Binding[,] ellipseBindings)
{
      ellipseBindings[i,j] = new Binding();
      ellipseBindings[i, j].Source = gameMatrix[i*gameColumn+ j];
      if (converter==null)
           converter = new VisibilityConverter();
      ellipseBindings[i, j].Converter = converter;
      circles[i, j] = new Ellipse();
      SolidColorBrush mySolidColorBrush = new SolidColorBrush();
      mySolidColorBrush.Color = Windows.UI.Color.FromArgb(255, 255, 106, 106);
      circles[i, j].Fill = mySolidColorBrush;
      circles[i, j].SetBinding(VisibilityProperty, ellipseBindings[i, j]);
      Grid.SetRow(circles[i, j], i);
      Grid.SetColumn(circles[i, j], j);
      gameFlat.Children.Add(circles[i, j]);
}

The circles and the ellipseBinds are declared in the GamePage.xaml.cs as well.

Ellipse[,] circles;
Binding[,] EllipseBindings;
VisibilityConverter converter;

The visibility of ellipses are controlled by the bool values in the first time, but when I try to change the bool value after the binding, in a time tick function of a timer, the change of bool values don't affect the ellipses.

private void timer_tick(object sender, object e)
{
    int testCount = pkgCountDown % (gameRow * gameColumn);
    gameMatrix[(testCount % gameRow)* gameColumn
       + pkgCountDown% gameColumn ] = true;
    gameCountDown--;
    pkgCountDown--;
} 

What's the wrong place in my code? Could you help me to make it work? Thank you!

-------update 2018/06/07--------

I tried to wrap the bool values in a class called isShownNotify which implements the INotifyPropertyChanged interface like below:

public class isShownNotify : INotifyPropertyChanged
{
     public event PropertyChangedEventHandler PropertyChanged;
     private bool _isShown;
     public bool isShown
     {
           get { return _isShown; }
           set
           {
               if (_isShown != value)
               {
                    isShown = value;               
               }
               OnPropertyChanged();
            }
     }
     public void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string name = "")
     {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler!=null)
            handler(this, new PropertyChangedEventArgs(name));
     }
}

Then I changed the converter like below:

object IValueConverter.Convert(object value, Type targetType, object parameter, string language)
{
    Type objectType = value.GetType();
    PropertyInfo objectInfo = objectType.GetProperty("isShown");
    bool boolValue = (bool)objectInfo.GetValue(value, null);
    if (boolValue == true)
        return Visibility.Visible;
    else
        return Visibility.Collapsed;
}

But in the running of the program, the changes on bool values still don't change the visibility of my Ellipses.

When I set breakpoints in the OnPropertyChanged() function, I see that the value of PropertyChanged(the PropertyChangedEventHandler) is null. What's wrong with it? Do I bind it to the visibility of ellipses in a wrong way?

oda356
  • 15
  • 4
  • 1
    You are missing something called 'INotifyPropertyChanged', when the bool values changes, they have to notify the system saying that, *I have changed, so change the properties bound with me too*. For details, see this: https://stackoverflow.com/questions/7767218/why-does-the-binding-update-without-implementing-inotifypropertychanged – Muzib Jun 04 '18 at 05:56
  • I have updated my problem description, wrapping bool values in a class implementing INotifyPropertyChanged didn't solve the trouble, The value of PropertyChanged event handler is null. Can you help me? – oda356 Jun 07 '18 at 07:15

1 Answers1

0

@MD Muzibur Rahman's suggestion was correct. You need to define a custom class and implement INotifyPropertyChangedinterface for it. I saw that you've done it. That's great. But you said that it doesn't work. After checking your code, the issue was due to that you want to change the property's value dynamically, but you have not bound to your property in your binding like this binding.Path = new PropertyPath("IsShown");. That's the reason why it doesn't work for you.

I've made a simple code sample for your reference:

<StackPanel>
    <Grid Grid.Column="1" Grid.Row="0"  x:Name="gameFlat">
    </Grid>
    <Button Content="add" Click="Button_Click"></Button>
    <Button Content="Hide" Click="Button_Click_1"></Button>
</StackPanel>
public ObservableCollection<gameMatrix> gameMatrixlist;
Binding binding;
Ellipse ellipse;
private void addEllipse()
{
    gameMatrixlist = new ObservableCollection<gameMatrix>() { new gameMatrix() {IsShown = true } };

    binding = new Binding();
    binding.Source = gameMatrixlist[0];
    binding.Path = new PropertyPath("IsShown");
    binding.Converter = new VisibilityConverter();

    ellipse = new Ellipse();
    SolidColorBrush mySolidColorBrush = new SolidColorBrush();
    mySolidColorBrush.Color = Windows.UI.Color.FromArgb(255, 255, 106, 106);
    ellipse.Fill = mySolidColorBrush;
    ellipse.Height = 100;
    ellipse.Width = 100;
    ellipse.SetBinding(VisibilityProperty, binding);

    Grid.SetRow(ellipse, 0);
    Grid.SetColumn(ellipse, 0);
    gameFlat.Children.Add(ellipse);
}

private void Button_Click(object sender, RoutedEventArgs e)
{
    addEllipse();
}

private void Button_Click_1(object sender, RoutedEventArgs e)
{
    gameMatrixlist[0].IsShown = false;
}

public class gameMatrix : INotifyPropertyChanged
{
    private bool _IsShown;
    public bool IsShown
    {
        get { return _IsShown; }
        set
        {
            if (value == _IsShown) return;
            _IsShown = value;
            OnPropertyChanged("IsShown");
        }
    }


    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}
public class VisibilityConverter:IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        if (value != null)
        {
            bool boolValue =  (bool)value;
            if (boolValue == true)
                return Visibility.Visible;
            else
                return Visibility.Collapsed;
        }
        return Visibility.Collapsed;


    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        return Visibility.Collapsed;
    }
}
Xie Steven
  • 8,544
  • 1
  • 9
  • 23
  • Do you mean I should reset a new bind to the ellipse every time I change the corresponding bool value? If so, why controls like ListView can show the change happens on the data model? Thank you. – oda356 Jun 17 '18 at 10:34