我的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>