c# - 如何在 ResourceDictionary / 模板文档中通过 Trigger/Setter 更新值时保持双向绑定
问题描述
<Grid x:Name="RedGrid" Visibility="{Binding Path=IsVisible,
Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
如您所见,此 Grid 的 Visibility 与 IsVisible 属性相关联。
<DataTemplate.Triggers>
<Trigger SourceName="RedGrid" Property="Opacity" Value="0">
<Setter TargetName="RedGrid" Property="Visibility" Value="Collapsed"/>
</Trigger>
</DataTemplate.Triggers>
一旦不透明度达到/等于零,这部分代码将改变 RedGrid 的可见性
但显然第二部分代码不起作用,因为当 RedGrid 的 Visibility 成功更改为 Collapsed 时,不会调用 IsVisible 的 Setter。
public Visibility IsVisible
{
get => _isVisible;
set
{
_isVisible = value;
RaisePropertyChanged("IsVisible");
}
}
解决方案
What you are trying to do is to update the Visibility
property of the Grid
using a Setter
and maintain the binding at the same time. The problem is that binding is overwritten by the Setter
!
When you use Xaml Setters you set properties the same way as you set them in the tag, so when you write:
<Setter TargetName="RedGrid" Property="Visibility" Value="Collapsed"/>
It acts the same way as if you've written:
<Grid x:Name="RedGrid" Visibility="Collapsed">
Notice that the binding Visibility="{Binding Path=IsVisible"}
has been overwritten by the value Visibility="Collapsed"
and will no longer work.
But Why?
The way that TwoWay
binding works can be found inside the controls themselves. When you work with DependencyProperties by default you set them using SetValue()
method, which sets the property's value and overwrites any binding in place.
However, in controls like TextBox
or CheckBox
that take in user input, when the user interacts with them, properties like TextBox.Text
and CheckBox.IsChecked
are being set by the method SetCurrentValue()
which like the documentation says:
The SetCurrentValue method changes the effective value of the property, but existing triggers, data bindings, and styles will continue to work.
You can review this question for more information about the differences between SetValue()
and SetCurrentVaule()
methods.
What to do:
In your case, I think that you can add a GridOpacity
property to the view model, and instead of changing the Visibility
in Xaml using a Setter
, you can change the view model's IsVisible
property directly when you set the GridOpacity
property.
Here is a sample code of the view model:
private Visibility _isVisible;
public Visibility IsVisible
{
get => _isVisible;
set
{
if (_isVisible == value)
{
return;
}
_isVisible = value;
RaisePropertyChanged(nameof(IsVisible));
}
}
private double _gridOpacity;
public double GridOpacity
{
get => _gridOpacity;
set
{
if (_gridOpacity == value)
{
return;
}
_gridOpacity = value;
RaisePropertyChanged(nameof(GridOpacity));
// Change the visibility of the grid when opacity hits 0.
if (value == 0)
{
IsVisible = Visibility.Collapsed;
}
else
{
// Change it back.
IsVisible = Visibility.Visible;
}
}
}
And here is the Xaml:
<Grid x:Name="RedGrid" Visibility="{Binding IsVisible}" Opacity="{Binding GridOpacity}">
...
</Grid>
推荐阅读
- cloudera - HUE中的打字问题
- java - 如何让 ScheduledExecutorService 在预定时间之前运行 Runnable?
- c# - 使用 msbuild 构建解决方案后出现错误 MSB4062
- wpf - 使用 MVVM 在 LoginView 和 MainView 之间切换
- scala - 使用名称中带有破折号的 Akka HTTP 参数
- java - 如何将 TextView 添加到 ScrollView
- python-3.x - 返回 Random.randint
- html - 以管理员身份编辑其他用户,ruby on rails
- laravel - 保存后如何在laravel vue中重新加载页面?
- python - 如何创建一个包含每只股票所有统计数据的唯一数据框?