简体   繁体   English

TextBlock文本属性在更新其源Binding属性时未更新吗?

[英]TextBlock Text property not updating on updating its source Binding property?

I have the following code snippet in XAML. 我在XAML中有以下代码片段。

<Grid>

    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="01*"/>
        <ColumnDefinition Width="03*"/>
        <ColumnDefinition Width="01*"/>
    </Grid.ColumnDefinitions>

    <Button Name="btnPrevious" Grid.Column="0" Content="Previous" Click="btnPrevious_Click"/>
    <TextBlock Name="txtBlockName" Grid.Column="1" Text="{Binding SelectedName, UpdateSourceTrigger=PropertyChanged}" FontSize="30" VerticalAlignment="Center" HorizontalAlignment="Center"/>
    <Button Name="btnNext" Grid.Column="2" Content="Next"  Click="btnNext_Click"/>

</Grid>

This generates the following output as in Figure1. 这将产生以下输出,如图1所示。

图1。

The code behind this is shown below. 其背后的代码如下所示。

public partial class MainWindow : Window, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public List<string> namesList = new List<string>();

    public string SelectedName
    {
        get
        {
            return namesList[1];
        }
        set
        {
            if (value != namesList[1])
            {
                namesList[1] = value;
                NotifyPropertyChanged("SelectedName");
            }
        }
    }

    public MainWindow()
    {
        InitializeComponent();

        namesList.Add("ABC");
        namesList.Add("DEF");
        namesList.Add("GHI");


        this.DataContext = this;
    }

    private void btnPrevious_Click(object sender, RoutedEventArgs e)
    {
        string str = namesList[0];
        namesList[0] = namesList[1];
        namesList[1] = str;

        this.IsEnabled = false;
    }

    private void btnNext_Click(object sender, RoutedEventArgs e)
    {
        string str = namesList[2];
        namesList[2] = namesList[1];
        namesList[1] = str;

        this.IsEnabled = false;
    }



    protected void NotifyPropertyChanged(String propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

}

The Text property of TextBlock is bound to the SelectedName property. TextBlockText属性绑定到SelectedName属性。 And it is not being updated on updating the SelectedName property. 并且在更新SelectedName属性时不会对其进行更新。 Although my class implements the INotifyPropertyChanged interface and defines its NotifyPropertyChanged behavior, it still doesn't work. 尽管我的类实现了INotifyPropertyChanged接口并定义了其NotifyPropertyChanged行为,但仍然无法正常工作。

While debugging, I put some break points to watch SelectedName property value and I observe that it is updating as per requirement but the Text property of TextBlock is not updating. 在调试时,我放置了一些断点来监视SelectedName属性值,并且观察到它正在按要求更新,但是TextBlockText属性没有更新。 As shown in Figure2. 如图2所示。

图2。

I have seen a lot of questions and solutions on Internet, but nothing solves my problem. 我在Internet上看到了很多问题和解决方案,但是没有什么可以解决我的问题。 Any help would be appreciated. 任何帮助,将不胜感激。

Of the two answers given so far, the only one that comes even close to what I think is a reasonable alternative is the second option presented in this answer (ie after "if you want to 'Update' SelectedName you could" ). 到目前为止给出的两个答案中,唯一接近我认为是合理的选择的是此答案中提供的第二个选项(即“如果您想'更新'SelectedName,则可以”之后 )。

That said, it seems to me that you would do well to change your data structure so that it more closely models what is actually happening in the user interface. 就是说,在我看来,您最好更改数据结构,以使其更紧密地建模用户界面中实际发生的事情。 Your code will be a lot easier to write and understand, and will be simpler, if you take the time to do so. 如果您愿意的话,您的代码将更容易编写和理解,并且会更简单。

In this particular example, that means that, since (it appears) you want to be able to navigate through three different text values, you should use the property simply to present the current text value, and use an index variable to keep track of which value is selected. 在此特定示例中,这意味着,由于您希望能够(通过它出现)浏览三个不同的文本值,因此应仅使用该属性来表示当前文本值,并使用索引变量来跟踪哪个值已选择。 For example: 例如:

public partial class MainWindow : Window, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    // Don't make fields public. If you do want to expose the list
    // use a public read-only property. And even there, think carefully
    // about whether you want callers to be able to modify the list; you
    // can return a `ReadOnlyCollection<string>` that wraps your list if
    // you only want callers to be able to examine the contents, rather than
    // modify it.
    //
    // Also, make any field that you never change "readonly".
    private readonly List<string> namesList = new List<string>();

    // Here's the index that keeps track of which string is selected
    private int _index;

    public string SelectedName
    {
        get { return namesList[_index]; }
    }

    public MainWindow()
    {
        InitializeComponent();

        namesList.Add("ABC");
        namesList.Add("DEF");
        namesList.Add("GHI");

        this.DataContext = this;
    }

    private void btnPrevious_Click(object sender, RoutedEventArgs e)
    {
        if (_index > 0)
        {
            _index--;
            NotifyPropertyChanged(nameof(SelectedName));
        }

        // I don't know what you expect this to do. You are setting the window's
        // "IsEnabled" property to false, which doesn't seem useful. More likely,
        // you intend to set the "Previous" button's enabled state, but even there
        // you really only want to set it to false if the _index value is 0. If the
        // _index value had been 2 and was just set to 1, you still want the
        // "Previous" button enabled. This would actually be an excellent place for
        // you to learn how to implement an ICommand, to have its CanExecute() method
        // return a value based on the _index value (where the "Previous" ICommand
        // object would return true unless _index is 0, and the "Next" ICommand
        // object would return true unless _index is namesList.Count - 1). Then you
        // can bind the button's "Command" property to the appropriate ICommand
        // object for the button and WPF will automatically deal with enabling
        // or disabling the button according to the command's state
        this.IsEnabled = false;
    }

    private void btnNext_Click(object sender, RoutedEventArgs e)
    {
        if (_index < namesList.Count - 1)
        {
            _index++;
            NotifyPropertyChanged(nameof(SelectedName));
        }

        // See comment above.
        this.IsEnabled = false;
    }

    protected void NotifyPropertyChanged(String propertyName)
    {
        PropertyChanged?.DynamicInvoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Note that with any of the changes proposed in either of the two other answers, you are still left with bugs related to the navigation between each text value. 请注意,通过其他两个答案中的任何一个提出的任何更改,您仍然留下与每个文本值之间的导航相关的错误。 The initial click of a button may work, but after that your data structure would be incoherent and you would not get the results it appears that you want. 初次单击按钮可能会起作用,但是此后您的数据结构将变得不连贯,并且您将无法获得想要的结果。

The example in this answer addresses all of those issues, along with your original concern. 此答案中的示例解决了所有这些问题以及您最初的关注。

You are never setting "SelectedName", you could've made it readonly. 您永远不会设置“ SelectedName”,可以将其设置为只读。

PropertyChanged is never raised. PropertyChanged永远不会引发。

If you want the binding to notice it, you should do 如果您想让绑定注意到它,您应该这样做

NotifyPropertyChanged("SelectedName");

after you have changed the index #1 of _namesLIst, 更改_namesLIst的索引#1后,

public partial class MainWindow : Window , INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private readonly List<string> _namesList = new List<string>();

    public string SelectedName
    {
        get { return _namesList[1]; }            
    }

    public MainWindow()
    {
        InitializeComponent();

        _namesList.Add("ABC");
        _namesList.Add("DEF");
        _namesList.Add("GHI");

        DataContext = this;
    }

    private void btnPrevious_Click(object sender, RoutedEventArgs e)
    {
        var str = _namesList[0];
        _namesList[0] = _namesList[1];
        _namesList[1] = str;
        NotifyPropertyChanged(nameof(SelectedName));
        IsEnabled = false;
    }

    private void btnNext_Click(object sender, RoutedEventArgs e)
    {
        var str = _namesList[2];
        _namesList[2] = _namesList[1];
        _namesList[1] = str;
        NotifyPropertyChanged(nameof(SelectedName));

        IsEnabled = false;
    }

    private void NotifyPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

}

if you want to 'Update' SelectedName you could 如果要“更新” SelectedName,可以

    public string SelectedName
    {
        get { return _namesList[1]; }
        set
        {
            if (value == _namesList[1]) return;
            _namesList[1] = value;
            NotifyPropertyChanged("SelectedName");
        }
    }

    private void btnPrevious_Click(object sender, RoutedEventArgs e)
    {
        var str = _namesList[0];
        _namesList[0] = _namesList[1];
        SelectedName = str;            
        IsEnabled = false;
    }

    private void btnNext_Click(object sender, RoutedEventArgs e)
    {
        var str = _namesList[2];
        _namesList[2] = _namesList[1];
        SelectedName = str;            
        IsEnabled = false;
    }

SelectedName Setter property has never been invoked. SelectedName Setter属性从未被调用过。 So you can update the TextBlock.Text by using BindingExpression.UpdateSource() method like below, 因此,您可以使用BindingExpression.UpdateSource()方法更新TextBlock.Text,如下所示,

 private void btnPrevious_Click(object sender, RoutedEventArgs e)
    {
        string str = namesList[0];
        namesList[0] = namesList[1];
        namesList[1] = str;
        BindingExpression be = txtBlockName.GetBindingExpression(TextBlock.TextProperty);
        be.UpdateSource();

        this.IsEnabled = false;
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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