Reputation: 561
I have a problem with updating my bindings. But I think the easiest way to explain my problem is my code:
XAML
<StackPanel>
<StackPanel.Resources>
<Converter:Converter_Position x:Key="Position"/>
</StackPanel.Resources>
<TextBox Text="{Binding Path=Position.X, UpdateSourceTrigger=PropertyChanged}"/>
<TextBox Text="{Binding Path=Position, Converter={StaticResource PositionToStartPosition}, UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
If I change the Text of the first TextBox the second TextBox does not update.
My Converter:
class Converter_Position : IValueConverter
{
public object Convert(object value, Type t, object parameter, CultureInfo culture)
{
RaPoint Position = value as RaPoint;
return Position.ToString();
}
public object ConvertBack(object value, Type t, object parameter, CultureInfo culture)
{
throw new Exception();
}
}
Bond Class:
public class RaPoint : INodifyPropertyChanged
{
public RaPoint()
{
X = 0;
Y = 0;
}
public RaPoint(double X, double Y)
{
this.X = X;
this.Y = Y;
}
private const string XPropertyName = "X";
private double _X;
public double X
{
get
{
return _X;
}
set
{
_X = value;
RaisePropertyChanged(XPropertyName);
}
}
private const string YPropertyName = "Y";
private double _Y;
public double Y
{
get
{
return _Y;
}
set
{
_Y = value;
RaisePropertyChanged(YPropertyName);
}
}
public override string ToString()
{
return String.Format("X:{0} Y:{1}" , X.ToString(), Y.ToString());
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
DataContext:
private const string PositionPropertyName = "Position";
private RaPoint _Position = new RaPoint();
public RaPoint Position
{
get
{
return _Position;
}
set
{
_Position = value;
RaisePropertyChanged(PositionPropertyName);
}
}
Upvotes: 1
Views: 5469
Reputation: 39386
If you are setting the DataContext
of your Window with a RaPoint
instance (Position
property), then you should try binding this way:
<TextBox Text="{Binding Path=X, UpdateSourceTrigger=PropertyChanged}"/>
<TextBox Text="{Binding Converter={StaticResource PositionToStartPosition}, UpdateSourceTrigger=PropertyChanged}"/>
Basically, a data binding establishes a connection between two properties of different objects. In the first line you are binding a property of the object you set in the the DataContext. Path
is used to specify a property of that object or might point to a property of a property (imagine X would have a property Z, then you could do something like Path=X.Z
).
About the second TextBox
, If you don't specify binding's Source
, Path
, RelativeSource
or ElementName
the Binding uses control's DataContext. The DataContext
is passed through the visual tree from upper element (e.g. Window) to the lower ones (TextBox
in your case).
But those suggestions are not going to resolve your problem. When you change the value of X
in the first TextBox, the Position
property never change, so the RaisePropertyChanged
is not going to be called and the second TextBox is not going to be updated with the new value of X. If you want to have a TextBox with both values of X
and Y
, then use a MultiBinding. In your Window/UserControl do this:
<TextBox Text="{Binding Path=X, UpdateSourceTrigger=PropertyChanged}"/>
<TextBox>
<TextBox.Text>
<MultiBinding Converter="{StaticResource Position}">
<Binding Path="X" />
<Binding Path="Y" />
</MultiBinding>
</TextBox.Text>
</TextBox>
And change your converter this way:
public class Converter_Position : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return String.Format("X:{0} Y:{1}", values[0],values[1]);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Upvotes: 1
Reputation: 17402
The problem is that the converter is only getting used once, upon load. The Position
DataContext
never changes, so there is no point in having a RaisePropertyChnage
inside the setter of the Position property. Remove that.
public RaPoint Position
{
get
{
return _Position;
}
set
{
_Position = value;
RaisePropertyChanged(PositionPropertyName);
}
}
to
public RaPoint Position
{
get; set;
}
The next thing is that you want the TextBox
to be updated whenever X
does, so ideally, you do not want to bind to simply just Position
(since the DataContext
is only getting changed once), you want to bind to Position.X
because that's where the property changed event is. By doing so, the converter will evaluate each time X
changes. You also want just the Position
class though, passed in the converter. You will need to update the converter so that the Position
is passed into it. The easiest way is to use a MultiValuConverter to pass into the Parameter object and also Paramter.X (which is going to be used to monitor the changes).
<TextBox>
<TextBox.Text>
<MultiBinding Converter="{StaticResource PositionToStartPosition}">
<Binding Path="Position.X" UpdateSourceTrigger="PropertyChanged"/>
<Binding Path="Position" />
</MultiBinding>
</TextBlock.Text>
</TextBox>
Lastly, update your converter:
class Converter_Position : IMultiValueConverter
{
public object Convert(object[] values, Type t, object parameter, CultureInfo culture)
{
RaPoint Position = values[1] as RaPoint;
return Position.ToString();
}
public object ConvertBack(object[] values, Type t, object parameter, CultureInfo culture)
{
throw new Exception();
}
}
Upvotes: 0