我在XAML中有以下代码片段。
Communication link failure due to underlying exception:
**BEGIN NESTED EXCEPTION**
java.net.ConnectionException
MESSAGE: connection timed out......
这将生成以下输出,如图1所示。
这背后的代码如下所示。
<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>
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));
}
}
的{{1}}属性绑定到Text
属性。并且没有更新TextBlock
属性的更新。虽然我的类实现了SelectedName
接口并定义了它的SelectedName
行为,但它仍然无法正常工作。
在调试时,我设置了一些断点来监视INotifyPropertyChanged
属性值,我发现它根据需要进行了更新,但NotifyPropertyChanged
的{{1}}属性没有更新。如图2所示。
我在互联网上看到了很多问题和解决方案,但没有解决我的问题。任何帮助将不胜感激。
答案 0 :(得分:1)
在目前为止给出的两个答案中,唯一一个与我认为合理的替代方案相近的是this answer中提出的第二个选项(即在&#34之后;如果你想要的话要更新&#39; SelectedName你可以&#34; )。
那就是说,在我看来,你最好改变你的数据结构,以便更接近地模拟用户界面中实际发生的事情。如果您花时间这样做,您的代码将更容易编写和理解,并且会更简单。
在这个特定的例子中,这意味着,因为(看起来)你希望能够浏览三个不同的文本值,你应该只使用该属性来呈现当前文本值,并使用索引变量来保持跟踪选择的值。例如:
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));
}
}
请注意,对于其他两个答案中的任何一个中提出的任何更改,您仍然会遇到与每个文本值之间的导航相关的错误。初始点击按钮可能会起作用,但之后您的数据结构会不连贯,您将无法获得所需的结果。
本回答中的示例解决了所有这些问题以及您最初的担忧。
答案 1 :(得分:0)
您永远不会设置“SelectedName”,您可以将其设为只读。
永远不会引发PropertyChanged。
如果您希望绑定通知它,您应该
NotifyPropertyChanged("SelectedName");
更改_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));
}
}
如果你想'更新'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;
}
答案 2 :(得分:0)
从未调用过SelectedName Setter属性。所以你可以使用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;
}