-3

My WPF binding is not working because my viewmodel has overwritten Equals and GetHashCode. If i comment it out (region Object-Stuff), everything works fine.

Further info about my reasons: All my viewmodels have an Id. I load data with Id=1 and set the datacontext. Later i reload the data (same id, but other properties can have changed), i reset the datacontext and nothing happens (DataContextChanged-event is raised). And for everybody who want to mark this as duplicate... No, i did not forget the INotifyPropertyChanged-Interface. The binding is refreshed when the datacontext is set, this has nothing to do with INotifyPropertyChanged.

Has anybody an idea how to refresh the datacontext? (by the way, set it to null and then to my new viewmodel is not an solution because the regulation is that a views datacontext is never null). Here is some small demo code to reproduce this. Window.xaml:

<Grid>
    <Button Content="Button1" HorizontalAlignment="Left" Margin="565,84,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
    <TextBox HorizontalAlignment="Left" Height="23" Margin="206,173,0,0" TextWrapping="Wrap" Text="{Binding Text}" VerticalAlignment="Top" Width="120"/>
    <Button Content="Button2" HorizontalAlignment="Left" Margin="565,138,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click_1"/>
    <Button Content="Button3" HorizontalAlignment="Left" Margin="565,191,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click_2"/>
</Grid>

Window.xaml.cs:

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        ViewModel vm = new ViewModel { Id = 1, Text = "Button1" };
        DataContext = vm;
    }

    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        ViewModel vm = new ViewModel { Id = 1, Text = "Button2" };
        DataContext = vm;
    }

    private void Button_Click_2(object sender, RoutedEventArgs e)
    {
        ViewModel vm = new ViewModel { Id = 1, Text = "Button3" };
        DataContext = vm;
    }

ViewModel:

class ViewModel
{
    public int Id { get; set; }
    public string Text { get; set; }

    #region Object-Stuff

    public override int GetHashCode()
    {
        return Id.GetHashCode();
    }

    public override bool Equals(object obj)
    {
        ViewModel other = obj as ViewModel;
        if ((object)other == null)
        {
            return false;
        }

        return Id == other.Id;
    }

    public virtual bool Equals(ViewModel other)
    {
        if ((object)other == null)
        {
            return false;
        }

        return Id == other.Id;
    }
    #endregion
}
Dosihris
  • 145
  • 9
  • actually this looks like a bug in WPF. – Dosihris Dec 31 '19 at 11:24
  • Why do you mean by saying nothing happens? Your code snippet doesn't show any binding, actually – Pavel Anikhouski Dec 31 '19 at 11:27
  • I bound the Textbox to the Textproperty ("Text="{Binding Text}"") If you try this code without the equals and gethashcode-code, you will see the bound value in the textbox. – Dosihris Dec 31 '19 at 11:29
  • Because all your VMs are equal in this case, and datacontext isn't changed due to `Equals()` override. You can INPC for that, obviously – Pavel Anikhouski Dec 31 '19 at 11:54
  • You're right Pavel, but INPC is not working on the Text-Property, like other people said. I have to build a new hierarchy of viewmodel and use it there, than it works for the entire viewmodel. – Dosihris Dec 31 '19 at 12:19
  • 1
    You already have the same question [WPF Binding not refreshing if Equals and GetHashCode](https://stackoverflow.com/questions/59538438/wpf-binding-not-refreshing-if-equals-and-gethashcode) – Pavel Anikhouski Dec 31 '19 at 13:20
  • oh, sorry. After clemens marked it as duplicate i got the following text: "Your post has been associated with a similar question. If this question doesn’t resolve your question, ask a new one." So i asked asked a new one, like it was said. – Dosihris Dec 31 '19 at 13:54
  • So what about the answer from this post? Can you put it to the other post? – Dosihris Dec 31 '19 at 13:55

1 Answers1

-1

So, for everybody who's interessted in this. This is a bug in WPF. The behaviour is strange, because sometimes the binding works, but most of the time the textbox in this example is not refreshed.

Everything in WPF works with the INotifyPropertyChanged-Interface, designed to inform the UI about changes in the data. If i would use this with a master viewmodel, it works. (But in spite of this its not nice). I changed the code to the following and then it works:

MainWindow.xaml:

    <TextBox HorizontalAlignment="Left" Height="23" Margin="206,173,0,0" TextWrapping="Wrap" Text="{Binding ViewModel.Text}" VerticalAlignment="Top" Width="120"/>

MasterViewModel:

class MasterViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public void OnNotifyPropertyChanged(string propName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
    }

    private ViewModel _viewModel;

    public ViewModel ViewModel
    {
        get { return _viewModel; }
        set
        {
            _viewModel = value;
            OnNotifyPropertyChanged(nameof(ViewModel));
        }
    }
}

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    private MasterViewModel _vm = new MasterViewModel();
    public MainWindow()
    {
        InitializeComponent();
        DataContext = _vm;
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        _vm.ViewModel = new ViewModel { Id = 1, Text = "Button1" };
        //DataContext = vm;
    }

    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        _vm.ViewModel = new ViewModel { Id = 1, Text = "Button2" };
        //DataContext = vm;
    }

    private void Button_Click_2(object sender, RoutedEventArgs e)
    {
        _vm.ViewModel = new ViewModel { Id = 1, Text = "Button3" };
        //DataContext = vm;
    }
}

In the Viewmodel itself, there was no change! Happy new Year to everybody...

Dosihris
  • 145
  • 9