简体   繁体   中英

Property update doesn't trigger bound value update

I spent three days trying not to ask this question because there are already lots of answers but none has helped me to this moment.

I have a MainWindow with TabControl with a UserControl in it, I need to pass a property from MainWindow to the UserControl , and with the following code it works - UserControl shows "Default Value" text. But, whenever the value of that property on MainWindow changes, it doesn't propagate to UserControl and doesn't trigger its OnSelectedSegmentIdChange , I tried everything I could, please help.

MainWindow XAML

<Window x:Class="Content_Manager.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
        Title="MainWindow" Height="450" Width="800"
        xmlns:i="http://schemas.microsoft.com/xaml/behaviors" xmlns:usercontrols="clr-namespace:Content_Manager.UserControls"
        x:Name="mainWindow">
        
    <Grid>
      ...
    <ListView x:Name="lvSegments" 
              Grid.Column="0" 
              ItemsSource="{Binding Segments}"
              SelectionMode="Single"
              SelectionChanged="lvSegments_SelectionChanged">
      ...

    <TabControl Grid.Column="1">
        <TabItem Header="О Разделе">
            <usercontrols:SegmentInfoTab SelectedSegmentId="{Binding Path=SegmentId, ElementName=mainWindow}"/>            
    </TabItem>
        ...
    </TabControl>
</Grid>

MainWindow C#

public string SegmentId { get; set; } = "Default Value";

public MainWindow()
{
            InitializeComponent();
            DataContext = this;
            ...

    private void lvSegments_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        SegmentId = ((Segment)lvSegments.SelectedItem).Id;
    }
...

UserControl XAML

  ...
  x:Name="SegmentInfo">
    <Grid>
        <TextBox x:Name="txtName"                 
                 Text="{Binding SelectedSegmentId}"/>
  ...

UserControl C#

    public SegmentInfoTab()
    {
        InitializeComponent();
        DataContext = this;
    }

    public static readonly DependencyProperty SelectedSegmentProperty = DependencyProperty.Register("SelectedSegmentId",
        typeof(string),
        typeof(SegmentInfoTab),
        new PropertyMetadata(string.Empty, OnSelectedSegmentIdChanged));
    
    public string SelectedSegmentId {
        get => (string)GetValue(SelectedSegmentProperty);
        set => SetValue(SelectedSegmentProperty, value);
    }

    private static void OnSelectedSegmentIdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var newValue= e.NewValue as string;
    }

To support auto-updating, a property must either notify of its change, or it must be changed only through bindings.
In this case, you can implement two options:

  1. Implement the "MainWindow.SegmentId" property as a DependencyProperty.
  2. Remove "lvSegments_SelectionChanged" method and use binding instead:
    <ListView x:Name="lvSegments" 
              Grid.Column="0" 
              ItemsSource="{Binding Segments}"
              SelectionMode="Single"
              SelectedValuePath="Id"
              SelectedValue="{Binding Path=SegmentId, ElementName=mainWindow}">

how can you do that? isn't SelectedItem used to set the value?

If I understand correctly what you need:

    <ListView x:Name="lvSegments" 
              Grid.Column="0" 
              ItemsSource="{Binding Segments}"
              SelectionMode="Single">
      ...

    <TabControl Grid.Column="1">
        <TabItem Header="О Разделе">
            <usercontrols:SegmentInfoTab
                SelectedSegmentId="{Binding
                                    Path=SelectedItem.SegmentId,
                                    ElementName=lvSegments}"/>            
        </TabItem>

You must implement INotifyPropertyChanged on your property. See: How to: Implement Property Change Notification .

public class Segment : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private string _segmentId = "Default Value";
    public string SegmentId
    {
        get { return _segmentId; }
        set
        {
            if (value != _segmentId) {
                _segmentId = value;
                OnPropertyChanged();
            }
        }
    }

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM