WPF Textbox TwoWay binding in datatemplate not updating the source even on LostFocus

旧街凉风 提交于 2019-12-25 03:32:30

问题


I have an ObservableCollection<string> Tags as part of a custom object. I bind it to a DataTemplate in order to show all tags to the user with the following code:

<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>

Adding and removing items from the ObservableCollection works as expected.

In code I switch between edit and view mode by setting the Visibility of the corresponding PanelEditNoteTags and PanelPreviewNoteTags. This all good and working. But when I enter the edit mode and start typing new values for the tags in the TextBox the source doesn't get updated. I certainly know that the LostFocus event is raised when I press my Save button. I tried all UpdateSourceTrigger values, still the same.

Is it a problem related to two controls binding at the same time to the same value - the Label from PanelPreviewNoteTags and the TextBox from PanelEditNoteTags?

What am I missing here?


回答1:


@Clemens Thank you for the quick and accurate response :) Following is the working solution for future reference.

The solution is not to use ObservableCollection<string> Tags because as pointed by Clemens the {Binding ., Mode=TwoWay} does not work back to the source.

So I created a custom 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;
    }
}

And use it as ObservableCollection<Tag> Tags. Then bind to it like so

<TextBox Text="{Binding Content, Mode=TwoWay}" Tag="{Binding}"/>

I actually populate from and save to postgres database in a string array column, so I need to convert to and from string[]. These are my conversions:

string[] array = note.Tags.Select(item => item.Content).ToArray();
note.Tags = new ObservableCollection<Tag>((array.Select(item => new Tag() { Content = item }).ToList()));


来源:https://stackoverflow.com/questions/31109776/wpf-textbox-twoway-binding-in-datatemplate-not-updating-the-source-even-on-lostf

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!