0

I have a ListBox whose ItemSource is bound to a collection of PointStyleModel objects which is contained in my PointStylesViewModel. The PointStyleModel class has three properties: Size, Name, and Color (Color is of type GeoColor - a third party library object).

A TextBox is bound to the Name property. An xceed toolkit IntegerUpDown is bound to Size. An xceed toolkit ColorPicker is bound to Color.

Currently, whenever the user selects a new item on the list, the three controls are updated properly. But if the user were to change a value of the IntegerUpDown or the ColorPicker in the UI, and then select a different item in the list, the UI doesn't display the correct value. I don't want the properties being updated just because the user changes a value in the UI. The TextBox bound to Name works fine. I've tried the various binding modes and updatesourcetriggers but no luck.

Here's my model class:

public class PointStyleModel
{
    public int Size
    {
        get;
        set;
    }

    public string Name
    {
        get;
        set;
    }

    public GeoColor Color
    {
        get;
        set;
    }
}

Here's my viewmodel:

public class PointStylesViewModel : ViewModelBase //using Fody's PropertyChangedInterface in the base class
{
    public ObservableCollection<PointStyleModel> PointStyles { get; set; } //the listbox is bound to this

    public PointStyleModel SelectedPointStyle { get; set; } //bound to the listboxe's selected item

    public string PointStyleName { get { return SelectedPointStyle.Name; } }

    public Color PointStyleColor
    {
        get
        {
            return Color.FromArgb(SelectedPointStyle.Color.AlphaComponent, SelectedPointStyle.Color.RedComponent, SelectedPointStyle.Color.GreenComponent, SelectedPointStyle.Color.BlueComponent); //Need to convert GeoColor to Color
        }
    }

    public int PointStyleSize { get { return SelectedPointStyle.Size; } }

    public PointStylesViewModel()
    {
        PointStyles = new ObservableCollection<PointStyleModel>();
        AddDefaultPointStyles(); //add some default styles

        SelectedPointStyle = PointStyles.First(); //select the first item in the list when starting up
    }
}

Here's relevant sections of my view:

<TabItem DataContext="{Binding Path=PointStylesViewModel, Source={StaticResource ViewModelLocator}}">
    <Grid>
        <ListBox ItemsSource="{Binding PointStyles}" SelectedItem="{Binding SelectedPointStyle}" DisplayMemberPath="Name"/>
        <TextBox Text="{Binding PointStyleName, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
        <GroupBox Header="Paint">
            <Grid>
                <xctk:ColorPicker SelectedColor="{Binding Path=PointStyleColor, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" DisplayColorAndName="False" DisplayColorTooltip="True"/>
                <xctk:IntegerUpDown Value="{Binding PointStyleSize, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" Maximum="20" Minimum="0" />
            </Grid>
        </GroupBox>
    </Grid>
</TabItem>

Here's an example of the problem:

First I select an item in the listbox. Everything is populated correctly. enter image description here

Now I'll change the color size on the UI only: enter image description here

And then I'll select another item from the list: enter image description here

In the first pic, I select RedSquare6 and it populates the ColorPicker with the PointStyleColor property in my VM. It's getting that value from the SelectedPointStyle's Color property. This works fine.

In the 2nd image, I select a new color from the ColorPicker control, pink in this case. This should NOT CHANGE any property. I'm just changing the Control's color. RedSquare6's Color property should still be Red.

In the 3rd image, I select GreenSquare6. The ColorPicker control should display Green now, but it stays on Pink, and the PointStyleColor getter in my VM is no longer being hit.

Same for the Size IntegerUpDown control.

The color picker and intupdown did not update when selecting a new color. I noticed the properties were not being hit when changing the selection. The PointStyleName was though.

Edit: Here's my ViewModelBase:

using PropertyChanged;
using System.ComponentModel;

namespace WpfApp1.ViewModels
{
    /// <summary>
    /// A base model that fires Property Changed events as needed
    /// </summary>
    [AddINotifyPropertyChangedInterface]
    public class ViewModelBase : INotifyPropertyChanged
    {
        /// <summary>
        /// The event is fired when any child property changes its value
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged = (sender, e) => { };
    }
}

Here's a gif of what is happening. I'm testing the intupdown control here: enter image description here

As you can see above, as soon as I change the value of the IntUpDown to 8, it stays at that value even though the selected item is changing which should change the value to 6.

Edit: Here's a small sample app showing the issue: https://www.dropbox.com/s/l3gu3nj915cstoa/TestApp.zip?dl=0

pfinferno
  • 1,779
  • 3
  • 34
  • 62
  • From what I'm seeing, nothing is invoking `PointStyleSize` or `PointStyleColor`. When `SelectedPointStyle` is changed, there's no logic that tells the interface to change the Color or Size. – Chris Nov 15 '18 at 17:46
  • You're right. Would you happen to know, when using Fody's propertychanged, how to notify for other properties changing? – pfinferno Nov 15 '18 at 18:48

1 Answers1

0

First you need to implement INotifyPropertyChanged properly in ViewModelBase.

public event PropertyChangedEventHandler PropertyChanged;

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

Second need to use it on selected Item changed on PointStylesViewModel:

private PointStyleModel _selectedPointStyle;
public PointStyleModel SelectedPointStyle
{
    get => _selectedPointStyle;
    set
    {
        _selectedPointStyle = value;
        OnPropertyChanged();
        OnPropertyChanged(nameof(PointStyleColor)); 
        OnPropertyChanged(nameof(PointStyleSize)); 
    }
 }
Clayton Harbich
  • 505
  • 1
  • 7
  • 16
  • I get this error when changing it to TwoWay: System.Windows.Markup.XamlParseException: ''Set property 'Xceed.Wpf.Toolkit.ColorPicker.SelectedColor' threw an exception.' Line number '192' and line position '59'.' Inner Exception nvalidOperationException: A TwoWay or OneWayToSource binding cannot work on the read-only property 'PointStyleColor' of type 'WpfApp1.ViewModels.PointStylesViewModel'. – pfinferno Nov 15 '18 at 18:13
  • I don't want to change the value of the model's properties underneath. The user shouldn't be able to change any properties behind from UI. – pfinferno Nov 15 '18 at 18:40
  • What do you want the UI color change to change? – Clayton Harbich Nov 15 '18 at 18:55
  • So the user can change the color of the color picker control on the UI, but this should NOT change the "PointStyleColor". When the user selects a new item from the listbox, the color picker control should be updated, but it stays the same as the last color the user changed it to. This only happens if the user picks a new color from the color picker, otherwise it works. – pfinferno Nov 15 '18 at 18:58
  • I'm confused what you are wanting. What do you think the set Color should go to? A different property on the ViewModel? – Clayton Harbich Nov 15 '18 at 19:00
  • I added some more details below the images in my post. Please check! Thanks. – pfinferno Nov 15 '18 at 19:10
  • Saw your edit, but it still isn't working. As soon as the user changes the value on the UI, the getter is never called for the property when the selected item changes. The OnPropertyChanged event for it is hit, but not the getter. – pfinferno Nov 15 '18 at 22:32
  • Updated my post with a gif at the bottom to show exactly what is happening. – pfinferno Nov 15 '18 at 22:39
  • Updated to include size as well. – Clayton Harbich Nov 15 '18 at 22:51
  • Tried what you said, neither color or size work. I uploaded a small test app at the end of my post that will show the problem. – pfinferno Nov 15 '18 at 23:15
  • I can't run the project because I don't have a valid xceed license. The gif shows the color working as expected. What is it doing now that's not working? – Clayton Harbich Nov 16 '18 at 01:50
  • Hmm weird, xceed was just a free package from nuget I got. I guess I posted a bad example, but all of the models' size is 6, not 8. I didn't show the issue with the Color in the .gif, but it's the same problem as the Size property. It changes correctly until I change the size/color on the UI. After that, whenever I select a new item in the list, the size/color stay at the same value as what the user changed on the UI, instead of the selected model's size/color. So in the .gif when you see 8 as the size after I select a new model, it should go back to 6. – pfinferno Nov 16 '18 at 02:13