奇怪的WPF模板重新渲染

时间:2017-12-08 21:27:19

标签: wpf mvvm datatemplate

我的WPF应用程序正在使用MVVM模式,其中使用基于WPF类型的DataTemplate机制发现视图。

我有一个包含ListBox的View,ListBox中ViewModel类型的DataTemplate位于包含ListBox的Grid上的Resource中。

在这个DataTemplate中,我有一个自定义Button类,它有一个DependencyProperty,它绑定到底层ViewModel上的字符串属性。单击Button时,自定义Button类中的代码隐藏将从DependencyProperty中获取值并将其传递到模式对话框,从对话框中获取已编辑的值并更新DependencyProperty(然后通过绑定流动,回到ViewModel)。整个过程运作正常。

但是,第一次发生这种情况时,对话框渲染中的某些内容会导致WPF执行某些操作,从而导致重新呈现ListBox中的项目。因此,单击的实际Button与Visual Tree分离,绑定的对象是"断开连接"。这仅在应用程序运行期间第一次引发对话时发生。一旦发生,一切都很好,直到你重新启动应用程序。

我不知所措。我最好的猜测(基于我的自定义按钮的构造函数的调用堆栈)是某些东西导致WPF重新编译我的应用程序的资源(或者,至少,这一个View),但我无法想象,以及如何防止它(或在启动期间强制它发生)。

任何建议都很棒。谢谢!

大卫穆林 IMA Technologies

编辑:这是尝试显示代码的样子(省略锅炉板代码)

<Grid>
    <Grid.Resources>

        <DataTemplate DataType="{x:Type ct:RecordDisplayDataSourceAuthoringViewModel}">
            <ctConfigControls:SetInfoButton Info="{Binding AutoNewSetInfoXml.Value}" Content="Set Info" />
        </DataTemplate>

    </Grid.Resources>

    <!-- The DataSources property contains a list of RecordDisplayDataSourceAuthoringViewModel -->
    <ListBox Grid.Row="1" ItemsSource="{Binding Path=DataSources}" />
</Grid>

public class SetInfoButton : Button
{
    public static readonly DependencyProperty InfoProperty = DependencyProperty.Register("Info", typeof(string), typeof(SetInfoButton),
                        new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

    public string Info
    {
        get { return (string)GetValue(InfoProperty); }
        set { SetValue(InfoProperty, value); }
    }

    public SetInfoButton()
    {
        Click += new RoutedEventHandler(SetInfoButton_Click);
        Focusable = false;
    }

    void SetInfoButton_Click(object sender, RoutedEventArgs e)
    {
        string info = Info;
        if (SetInfoDialog.Show(VisualTreeHelperEx.FindVisualAncestor<Window>(this), ref info) == true)
        {
            Info = info;
        }
    }
}

public partial class SetInfoDialog : DialogWindow, IDesignerDataSource
{
    public static bool Show(Window parent, ref string info)
    {
        SetInfoDialog dlg = new SetInfoDialog(info);
        dlg.Owner = parent;
        if (dlg.ShowDialog() == true)
        {
            info = dlg.RawInfo;
            return true;
        }

        return false;
    }

    public SetInfoDialog(string rawInfo)
    {
        //...
    }
}

<ct:DialogWindow x:Class="CaseTrakker.Windows.Dialogs.SetInfoDialog">
    <ct:DialogWindow.Buttons>
        <ct:ImageButton Image="{DynamicResource {x:Static ct:Common.OkImageKey}}" Content="_Ok" Click="Ok_Click" />
        <ct:ImageButton Image="{DynamicResource {x:Static ct:Common.CancelImageKey}}" Content="_Cancel" Click="Cancel_Click" IsCancel="True" />
    </ct:DialogWindow.Buttons>

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <Grid Grid.Row="0" Grid.Column="0" Visibility="{Binding Path=HideObjectSelectorControls, Converter={StaticResource InvertedBoolToVisibilityConverter}}" >
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>

            <Label Grid.Row="0" Grid.Column="0">System Object</Label>
            <ct:SystemObjectComboBox Grid.Row="0" Grid.Column="1" CreateOnly="True" SelectedValue="{Binding Path=SystemObjectNumber}" />

            <Label Grid.Row="1" Grid.Column="0">Type</Label>
            <ctConfigControls:TemplateComboBox Grid.Row="1" Grid.Column="1" 
                                               SystemObject="{Binding Path=SystemObjectNumber, Converter={StaticResource IntToStandardSystemObjectConverter}}" 
                                               SelectedValue="{Binding Path=TemplateId}" />
        </Grid>

        <Button Grid.Row="0" Grid.Column="1" Click="Import_Click">Import</Button>
        <Grid Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <StackPanel Grid.Column="0" Orientation="Vertical" Margin="4,8,4,4"
                        Visibility="{Binding Path=DisplayText, Converter={StaticResource EmptyToVisibilityConverter}}">
                <Label FontWeight="Bold">Notes</Label>
            <TextBox Text="{Binding Path=DisplayText, Mode=OneWay}" IsReadOnly="True"/>
            </StackPanel>
            <ctConfigDesigner:DataDesigner x:Name="Designer" Grid.Column="1" Loaded="DataDesigner_Loaded" />
        </Grid>
    </Grid>   
</ct:DialogWindow>

<Style x:Key="DialogWindowStyle" TargetType="{x:Type ctWindows:DialogWindow}" BasedOn="{StaticResource {x:Type Window}}">
    <Setter Property="Background" Value="{DynamicResource {x:Static ctThemes:Common.StandardWindowBackgroundBrushKey}}" />
    <Setter Property="ContentTemplate">
        <Setter.Value>
            <DataTemplate>
                <Grid>
                    <Grid.LayoutTransform>
                        <ScaleTransform x:Name="ZoomFrame"
                                ScaleX="{Binding Path=ZoomValue, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ctWindows:DialogWindow}}}"
                                ScaleY="{Binding Path=ZoomValue, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ctWindows:DialogWindow}}}"/>
                    </Grid.LayoutTransform>

                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="*" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>

                    <Grid Grid.Row="0" Grid.Column="0">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto" />
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="Auto" />
                        </Grid.ColumnDefinitions>

                        <Image Grid.Row="0" Grid.Column="0" Height="35" Width="35" 
                                        Visibility="{Binding Path=HasTitleImage, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ctWindows:DialogWindow}}, Converter={StaticResource BoolToVisibilityConverter}}"
                                        Source="{Binding Path=TitleImage, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ctWindows:DialogWindow}}}" />

                        <Label Grid.Row="0" Grid.Column="1" Content="{Binding Path=Title, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ctWindows:DialogWindow}}}"
                                        Style="{DynamicResource LabelTitle}" FontWeight="Bold" />

                        <ContentControl Grid.Row="0" Grid.Column="2" 
                                        DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ctWindows:DialogWindow}}}"
                                        Content="{Binding Path=HeaderContent, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ctWindows:DialogWindow}}}" />
                    </Grid>


                    <ContentControl Grid.Row="1" Grid.Column="0" 
                                        DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ctWindows:DialogWindow}}}"
                                        Content="{Binding Path=WindowContent, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ctWindows:DialogWindow}}}" />

                    <ContentControl Grid.Row="2" Grid.Column="0" 
                                        DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ctWindows:DialogWindow}}}"
                                        Content="{Binding Path=ButtonPanel, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ctWindows:DialogWindow}}}" />
                </Grid>
            </DataTemplate>
        </Setter.Value>
    </Setter>
</Style>

0 个答案:

没有答案