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;
}
CodePudding user response:
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:
- Implement the "MainWindow.SegmentId" property as a DependencyProperty.
- 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}">
CodePudding user response:
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));
}
}