数据模板中的 WPF 文本框双向绑定即使在 LostFocus 上也不更新源
WPF Textbox TwoWay binding in datatemplate not updating the source even on LostFocus
我有一个 ObservableCollection<string> Tags
作为自定义对象的一部分。我将它绑定到 DataTemplate
以便使用以下代码向用户显示所有标签:
<StackPanel DockPanel.Dock="Top" Margin="15,0,15,0" Orientation="Horizontal">
<Label Content="Tags:" FontSize="14" Foreground="{StaticResource HM2LightTextBrush}"/>
<Grid>
<ItemsControl Name="PanelPreviewNoteTags" ItemsSource="{Binding ElementName=lbNotesQuickView, Path=SelectedItem.Tags}" Margin="3,0" Visibility="Collapsed">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderThickness="1" BorderBrush="#676B6E" Margin="3,0">
<Label Content="{Binding .,Mode=OneWay}" Foreground="{StaticResource HM2LightTextBrush}"/>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<ItemsControl Name="PanelEditNoteTags" ItemsSource="{Binding ElementName=lbNotesQuickView, Path=SelectedItem.Tags}" Margin="3,0" Visibility="Collapsed">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderThickness="1" BorderBrush="#676B6E" Margin="3,0">
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding ., Mode=TwoWay}"/>
<Button Style="{StaticResource RibbonButton}" Click="ButtonRemoveTagClick" Tag="{Binding}">
<Image Height="16" Width="16" Source="/Poker Assistant;component/Resources/fileclose.png" />
</Button>
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</StackPanel>
在 ObservableCollection
中添加和删除项目按预期工作。
在代码中,我通过设置相应PanelEditNoteTags
和PanelPreviewNoteTags
的Visibility
在编辑模式和查看模式之间切换。这一切都很好并且有效。但是当我进入编辑模式并开始为 TextBox
中的标签键入新值时,源代码不会更新。我当然知道当我按下 Save
按钮时会引发 LostFocus
事件。我试了所有UpdateSourceTrigger
值,还是一样。
问题是否与两个控件同时绑定到相同的值有关 - 来自 PanelPreviewNoteTags
的 Label
和来自 PanelEditNoteTags
的 TextBox
?
我在这里错过了什么?
@Clemens 感谢您快速准确的回复:) 以下是工作解决方案以供将来参考。
解决方案是不使用 ObservableCollection<string> Tags
,因为正如 Clemens 所指出的那样,{Binding ., Mode=TwoWay}
无法回到源头。
所以我创建了一个自定义 Tag
class:
public class Tag : INotifyPropertyChanged
{
private string _content;
public string Content { get { return _content; } set { _content = value; OnMyPropertyChanged(() => Content); } }
public Tag(string content)
{ Content = content; }
public Tag()
: this("new tag")
{ }
public event PropertyChangedEventHandler PropertyChanged;
// Raise the event that a property has changed in order to update the visual elements bound to it
internal void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
//CONVERTS the passed parameter to its name in string
internal void OnMyPropertyChanged<T>(Expression<Func<T>> memberExpression)
{
MemberExpression expressionBody = (MemberExpression)memberExpression.Body;
OnPropertyChanged(expressionBody.Member.Name);
}
public override string ToString()
{
return Content;
}
}
并将其用作ObservableCollection<Tag> Tags
。然后像这样绑定它
<TextBox Text="{Binding Content, Mode=TwoWay}" Tag="{Binding}"/>
我实际上是在字符串数组列中从 postgres 数据库填充和保存到 postgres 数据库,所以我需要与 string[] 相互转换。这些是我的转化次数:
string[] array = note.Tags.Select(item => item.Content).ToArray();
note.Tags = new ObservableCollection<Tag>((array.Select(item => new Tag() { Content = item }).ToList()));
我有一个 ObservableCollection<string> Tags
作为自定义对象的一部分。我将它绑定到 DataTemplate
以便使用以下代码向用户显示所有标签:
<StackPanel DockPanel.Dock="Top" Margin="15,0,15,0" Orientation="Horizontal">
<Label Content="Tags:" FontSize="14" Foreground="{StaticResource HM2LightTextBrush}"/>
<Grid>
<ItemsControl Name="PanelPreviewNoteTags" ItemsSource="{Binding ElementName=lbNotesQuickView, Path=SelectedItem.Tags}" Margin="3,0" Visibility="Collapsed">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderThickness="1" BorderBrush="#676B6E" Margin="3,0">
<Label Content="{Binding .,Mode=OneWay}" Foreground="{StaticResource HM2LightTextBrush}"/>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<ItemsControl Name="PanelEditNoteTags" ItemsSource="{Binding ElementName=lbNotesQuickView, Path=SelectedItem.Tags}" Margin="3,0" Visibility="Collapsed">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderThickness="1" BorderBrush="#676B6E" Margin="3,0">
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding ., Mode=TwoWay}"/>
<Button Style="{StaticResource RibbonButton}" Click="ButtonRemoveTagClick" Tag="{Binding}">
<Image Height="16" Width="16" Source="/Poker Assistant;component/Resources/fileclose.png" />
</Button>
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</StackPanel>
在 ObservableCollection
中添加和删除项目按预期工作。
在代码中,我通过设置相应PanelEditNoteTags
和PanelPreviewNoteTags
的Visibility
在编辑模式和查看模式之间切换。这一切都很好并且有效。但是当我进入编辑模式并开始为 TextBox
中的标签键入新值时,源代码不会更新。我当然知道当我按下 Save
按钮时会引发 LostFocus
事件。我试了所有UpdateSourceTrigger
值,还是一样。
问题是否与两个控件同时绑定到相同的值有关 - 来自 PanelPreviewNoteTags
的 Label
和来自 PanelEditNoteTags
的 TextBox
?
我在这里错过了什么?
@Clemens 感谢您快速准确的回复:) 以下是工作解决方案以供将来参考。
解决方案是不使用 ObservableCollection<string> Tags
,因为正如 Clemens 所指出的那样,{Binding ., Mode=TwoWay}
无法回到源头。
所以我创建了一个自定义 Tag
class:
public class Tag : INotifyPropertyChanged
{
private string _content;
public string Content { get { return _content; } set { _content = value; OnMyPropertyChanged(() => Content); } }
public Tag(string content)
{ Content = content; }
public Tag()
: this("new tag")
{ }
public event PropertyChangedEventHandler PropertyChanged;
// Raise the event that a property has changed in order to update the visual elements bound to it
internal void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
//CONVERTS the passed parameter to its name in string
internal void OnMyPropertyChanged<T>(Expression<Func<T>> memberExpression)
{
MemberExpression expressionBody = (MemberExpression)memberExpression.Body;
OnPropertyChanged(expressionBody.Member.Name);
}
public override string ToString()
{
return Content;
}
}
并将其用作ObservableCollection<Tag> Tags
。然后像这样绑定它
<TextBox Text="{Binding Content, Mode=TwoWay}" Tag="{Binding}"/>
我实际上是在字符串数组列中从 postgres 数据库填充和保存到 postgres 数据库,所以我需要与 string[] 相互转换。这些是我的转化次数:
string[] array = note.Tags.Select(item => item.Content).ToArray();
note.Tags = new ObservableCollection<Tag>((array.Select(item => new Tag() { Content = item }).ToList()));