卸载/重新加载视图

时间:2017-11-03 10:35:09

标签: .net wpf mvvm data-binding

我有一个非常奇怪和恼人的问题,我无法理解。这有点难以解释所以请耐心等待。

背景是我有一个有2个视图的应用程序,我可以在2之间来回切换。这是使用MVVM实现的,所以我有一个带有ContentControl的主窗口。 ContentControl的内容绑定到MainViewModel中的CurrentViewModel属性。 切换是通过使用命令绑定将CurrentViewModel设置为我的2个不同视图中的一个或另一个ViewModel。 2个ViewModel链接到App.xaml中的Views by DataTemplate定义。我相信这是一个相当常见的设置。 (注意,在当前实现中我使用MvvmLight并且ViewModel使用其SimpleIOC进行管理)

问题现在是如果我在一个视图中有一个ToggleButton,其中一些自定义内容(矩形和圆形)被绘制为切换/取消闭合状态。这是使用样式触发器(或DataTriggers)实现的。直到这里仍然没有问题,但如果我将Fill属性绑定到ToggleButton的前景颜色(请参阅下面的代码示例),会发生一些奇怪的事情:

  1. 切换按钮,切换到第二个视图,切换回来,取消切换按钮 - 不渲染图形(原因是Fill的绑定不起作用),但切换状态的其他内容没有问题
  2. 一旦未遮挡的绘图丢失,在此未遮挡状态下切换到第二个视图然后切换回 - 无遮挡状态下的绘图奇迹般地返回并且两个状态(切换/未遮挡)都正确呈现
  3. 修改 切换回时出的错误: System.Windows.Data错误:4:找不到引用'ElementName = TB1'的绑定源。 BindingExpression:路径=前景;的DataItem = NULL; target元素是'Ellipse'(Name =''); target属性为'Fill'(类型'Brush')

    任何人都知道问题的来源以及如何解决这个问题? 我正在考虑简化测试应用程序,排除所有MvvmLight / IOC,但我怀疑这个问题与此有关。

    <ToggleButton x:Name="TB1"  Grid.Row="0" Grid.Column="1" Margin="5" Width="30"
    Command="{Binding Toggle1}"
    IsChecked="{Binding IsToggled1}">
    <ToggleButton.Style>
        <Style TargetType="{x:Type ToggleButton}">
            <Setter Property="Content" >
                <Setter.Value>
                    <Rectangle Width="17" Height="17" Fill="{Binding ElementName=TB1, Path=Foreground}" />
                </Setter.Value>
            </Setter>
            <Style.Triggers>
                <DataTrigger Binding="{Binding IsToggled1}" Value="False">
                    <Setter Property="Content">
                        <Setter.Value>
                            <Ellipse Width="17" Height="17" Fill="{Binding ElementName=TB1, Path=Foreground}" />
                        </Setter.Value>
                    </Setter>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ToggleButton.Style>
    

1 个答案:

答案 0 :(得分:0)

您使用 XAML名称范围时遇到问题。它就像变量范围一样,仅适用于XAML名称。 XAML namescope是在XAML页面的根元素上创建的,但样式和模板有自己的名称范围,因为它们是可重用的。让我们说你的Style中的Rectangle或Ellipse有一个Name,你在视图中使用该样式有5个ToggleButtons。如果Styles没有自己的名称范围,那么在同一个名称范围内将有5个具有相同名称的元素。 解析XAML时,将应用其中一个Content属性值(取决于ToggleButton的IsChecked状态)。它进入TogglButton的名称范围并且ElementName被解析,但是另一个仍然在名称范围之外并且无法解析。

那你能做什么?您可以使用x:Reference标记扩展名。因此,您可以使用ElementName=TB1代替Source={x:Reference TB1}。但是然后XAML解析器会抛出一个循环依赖异常,因为你的引用会指向一个包含引用的元素(你的Style在你的ToggleButton中定义)。要解决此问题,请将您的样式定义为资源:

<Window.Resources>
  <Style x:key="TBStyle" TargetType="{x:Type ToggleButton}">
     <Setter Property="Content">
        <Setter.Value>
            <Rectangle Width="17" Height="17"
                     Fill="{Binding Foreground, Source={x:Reference TB1}}"/>
        </Setter.Value>
     </Setter>
     <Style.Triggers>
        <DataTrigger Binding="{Binding IsToggled1}" Value="False">
            <Setter Property="Content">
                <Setter.Value>
                    <Ellipse Width="17" Height="17"
                 Fill="{Binding Foreground, Source={x:Reference TB1}}}" />
                </Setter.Value>
            </Setter>
        </DataTrigger>
    </Style.Triggers>
  </Style>
</Window.Resources>
....
<ToggleButton x:Name="TB1"
              Margin="5"
              Width="30"
              Height="30"
              IsChecked="{Binding IsToggled1}"
              Style="{StaticResource TBStyle}"/>

如果您将此样式应用于5个ToggleButtons,它们都会从名为&#34; TB1&#34;的一个按钮中选择前景颜色,但这是完全不同的问题。