-1

When i set default values in my ViewModel, it works, but when i change anything, the View stays the same....so i think this has to do with INotifyPropertyChanged. I've spent about 10 hours "googleing", but i couldn't find out whats wrong. So here's my code, i hope you can tell me what's wrong :)

My View:

<UserControl x:Class="Diplomarbeit.Views.TasteView" 
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:Diplomarbeit"
         mc:Ignorable="d"
         >
<Grid>
    <Ellipse x:Name="Taste" Fill="{Binding FillColor, Mode=TwoWay}" Stroke="{Binding BorderColor, Mode=TwoWay}" StrokeThickness="10" Height="{Binding ActualWidth, RelativeSource={RelativeSource Self}}" Margin="2,0,2,0"/>
    <Viewbox>
        <Label x:Name="TasteText" Content="{Binding Text, Mode=TwoWay}" Foreground="{Binding TextColor, Mode=TwoWay}" FontWeight="ExtraBold" VerticalAlignment="Center" HorizontalAlignment="Center"/>
    </Viewbox>
</Grid>

Codebehind of the View:

    public partial class TasteView : UserControl
{
    public TasteView()
    {
        InitializeComponent();
        // DataContext der View auf ViewModel binden
        this.DataContext = new TasteViewModel();
    } 
}

My ViewModel:

public class TasteViewModel : INotifyPropertyChanged
{
    #region PropertyChanged-Event + Methode
    public event PropertyChangedEventHandler PropertyChanged; // Event wird deklariert

    private void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); // Event wird gefeuert
        }
    }
    #endregion

    #region Felder
    //ID für Eindeutigkeit
    private int _iD;
    //Füllfarbe der Ellipse
    private SolidColorBrush _fillColor;
    //Randfarbe der Ellipse
    private SolidColorBrush _borderColor;
    //Text der im Label steht; ACHTUNG: Vor und nach der Zahl 2 Leerzeichen!
    private string _text;
    //Farbe des Texts im Label
    private SolidColorBrush _textColor;
    #endregion

    #region Eigenschaften

    //ID für Eindeutigkeit
    public int ID
    {
        get { return _iD; }
        set
        {
            if (value != _iD)
            {
                _iD = value;
                OnPropertyChanged("ID");
            }
        }
    }

    //Füllfarbe der Ellipse
    public SolidColorBrush FillColor
    {
        get { return _fillColor; }
        set
        {
            if (value != _fillColor)
            {
                _fillColor = value;
                OnPropertyChanged("FillColor");
            }
        }
    }

    //Randfarbe der Ellipse
    public SolidColorBrush BorderColor
    {
        get { return _borderColor; }
        set
        {
            if (value != _borderColor)
            {
                _borderColor = value;
                OnPropertyChanged("BorderColor");
            }
        }
    }

    //Text der im Label steht
    public string Text 
    {
        get { return _text; }
        set
        {
            if (value != _text)
            {
                _text = value;
                OnPropertyChanged("Text");
            }
        }
    }

    //Farbe des Texts im Label
    public SolidColorBrush TextColor 
    {
        get { return _textColor; }
        set
        {
            if (value != _textColor)
            {
                _textColor = value;
                OnPropertyChanged("TextColor");
            }
        }
    }
    #endregion     

    #region Konstruktoren

    //Farbige Taste mit Border, Text und ID ==> Vollständige Taste 
    public TasteViewModel(int iD, SolidColorBrush fillColor, SolidColorBrush borderColor, string text, SolidColorBrush textColor)
    {
        iD = ID;
        fillColor = FillColor;
        borderColor = BorderColor;
        text = Text;
        textColor = TextColor;
    }

    //Farbige Taste mit Border und ID, jedoch ohne Text
    public TasteViewModel(int iD, SolidColorBrush fillColor, SolidColorBrush borderColor)
    {
        iD = ID;
        fillColor = FillColor;
        borderColor = BorderColor;
    }

    //Leere Taste, allerdings mit ID
    public TasteViewModel(int iD)
    {
        iD = ID;
    }

    //Leere Taste
    public TasteViewModel()
    {

    }
    #endregion
Stefan
  • 17,448
  • 11
  • 60
  • 79
  • One side step: try to look into `[CallerMemberName]`: see: http://jesseliberty.com/2012/06/28/c-5making-inotifypropertychanged-easier/ – Stefan Apr 18 '18 at 10:26
  • Another sidestep: why do you use 2way binding on a label? – Stefan Apr 18 '18 at 10:27
  • 2
    How are you changing the values? The rest seems in order. – Stefan Apr 18 '18 at 10:34
  • 2
    How do you set values of the view model after it was assigned to the DataContext? Im pretty sure you're not accessing the correct view model instance. And of course, a TwoWay Binding of a Label's Content property is pointless. – Clemens Apr 18 '18 at 10:39
  • As a a note, it may later turn out as a big mistake to explicitly set the UserControl's DataContext to an instance of a view model. Instead of operating on a "private" own instance of a view model, a UserControl should expose dependency properties that are bound to properties of an "externally supplied" view model instance. This is usually provided by means of property value inheritance of the DataContext property. The MainWindow for instance, sets its DataContext property, which is then automatically value-inherited by a UserControl in the MainWindow. – Clemens Apr 18 '18 at 10:45
  • And... the usage of `x:Name` suggests you set some data in the code behind, and not through the MVVM pattern. Is this correct? – Stefan Apr 18 '18 at 11:00
  • 1
    @David Now you have accepted an answer that (although useful) does not show a solution of your actual problem. It will remain a secret what you really did wrong. What is a SetMethod? – Clemens Apr 18 '18 at 11:14
  • Check your Output window. Probably you will see many Binding errors. If it is than I think your DataContext contains instance with type different than TasteViewModel. – Anton Apr 18 '18 at 11:22

3 Answers3

-1

I use this pattern with some helper attributes:

public class ViewModel: INotifyPropertyChanged
{
    private string _text;
    public string Text
    {
        get { return _text; }
        set
        {
            if (value == _text) return;
            _text= value;
            OnPropertyChanged();
        }
    }

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

It should work.

In any case, try to use the helpers. It protect you against non-strong-typed-typo's.

Stefan
  • 17,448
  • 11
  • 60
  • 79
-1

You have set invalid construtor in TasteView.Xaml.cs. It should be like

public TasteView()
{
    InitializeComponent();
    // DataContext der View auf ViewModel binden
    this.DataContext = new TasteViewModel(1,Brushes.Red,Brushes.Green,"Taste",Brushes.Blue);
} 

And that construtor should be like below.

public TasteViewModel(int iD, SolidColorBrush fillColor, SolidColorBrush borderColor, string text, SolidColorBrush textColor)
    {
        ID = iD;
        FillColor = fillColor;
        BorderColor = borderColor;
        Text = text;
        TextColor = textColor;
    }`

Hope this will work for you.

IndraJeyan
  • 119
  • 7
-2

Your contructors are wrong:

//Farbige Taste mit Border, Text und ID ==> Vollständige Taste 
    public TasteViewModel(int iD, SolidColorBrush fillColor, SolidColorBrush borderColor, string text, SolidColorBrush textColor)
    {
        ID = iD;
        FillColor = fillColor ;
        BorderColor = borderColor;
        Text = text;
        TextColor = textColor;
    }

same for the other two.

EDIT: two-way binding is the default behavior,no need to explicit it in your xaml.

if you are using c# 6 or newer you should use nameof() operator for OnPropertyChanged()

rmbq
  • 427
  • 4
  • 20