依赖属性不更新Visual Studio设计器

问题描述:

我已经创建了一个新的WPF Window类的样式,并在那里有一些依赖属性。需要注意的一个是依赖属性不更新Visual Studio设计器

ShowHelpButton

这应该切换窗口上的帮助按钮的可见性。该代码在运行时正常工作,但无法在设计视图中更新UI。

这里的类:

public class MainWindowFrame : Window 
{ 
    #region DependencyProperties 

    public static readonly DependencyProperty ShowHelpButtonProperty = DependencyProperty.Register(
    "ShowHelpButton", typeof (bool), typeof (MainWindowFrame), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.AffectsRender)); 

    public bool ShowHelpButton 
    { 
    get { return (bool) GetValue(ShowHelpButtonProperty); } 
    set { SetValue(ShowHelpButtonProperty, value); } 
    } 

    #endregion 


    static MainWindowFrame() 
    { 
    DefaultStyleKeyProperty.OverrideMetadata(typeof(MainWindowFrame), 
     new FrameworkPropertyMetadata(typeof(MainWindowFrame))); 
    } 

这里的风格:

<Style x:Key="MainWindowStyle" TargetType="{x:Type abstractClasses:MainWindowFrame}"> 
    <Setter Property="HorizontalAlignment" Value="Stretch" /> 
    <Setter Property="VerticalAlignment" Value="Stretch" /> 
    <Setter Property="AllowsTransparency" Value="True" /> 
    <Setter Property="Background" Value="{StaticResource LightBlueBrush}" /> 
    <Setter Property="BorderBrush" Value="{StaticResource BlueBrush}" /> 
    <Setter Property="BorderThickness" Value="1" /> 
    <Setter Property="CornerRadius" Value="1" /> 
    <Setter Property="ResizeMode" Value="NoResize" /> 
    <Setter Property="WindowStyle" Value="None" /> 
    <Setter Property="Title" Value="New Window" /> 
    <Setter Property="Template"> 
    <Setter.Value> 
     <ControlTemplate TargetType="{x:Type abstractClasses:MainWindowFrame}"> 
      <Border 
       Background="{TemplateBinding Background}" 
       BorderBrush="{TemplateBinding BorderBrush}" 
       BorderThickness="{TemplateBinding BorderThickness}" 
       CornerRadius="{TemplateBinding CornerRadius}"> 
       <Grid x:Name="ContainerGrid" Background="Transparent"> 
       <Grid.RowDefinitions> 
        <RowDefinition Height="Auto" /> 
        <RowDefinition Height="*" /> 
       </Grid.RowDefinitions> 
       <Grid.Triggers> 
        <EventTrigger RoutedEvent="Grid.Loaded"> 
         <BeginStoryboard> 
          <Storyboard> 
          <DoubleAnimation 
           Storyboard.TargetProperty="Opacity" 
           From="0" 
           To="1" 
           Duration="00:00:01" /> 
          </Storyboard> 
         </BeginStoryboard> 
        </EventTrigger> 
       </Grid.Triggers> 
       <Grid Background="Transparent" MouseDown="Window_MouseDownDrag"> 
        <Grid.ColumnDefinitions> 
         <ColumnDefinition Width="*" /> 
         <ColumnDefinition Width="Auto" /> 
         <ColumnDefinition Width="Auto" /> 
        </Grid.ColumnDefinitions> 
        <Grid Grid.Column="0"> 
         <TextBlock 
          Margin="10,3,0,3" 
          HorizontalAlignment="Left" 
          VerticalAlignment="Center" 
          Style="{StaticResource CustomTitleBarTextBlackB}" 
          Text="{TemplateBinding Title}" /> 
        </Grid> 
        <Button 
         Grid.Column="1" 
         Width="20" 
         Height="20" 
         Margin="0,0,5,0" 
         HorizontalAlignment="Right" 
         AutomationProperties.AutomationId="Help" 
         Style="{StaticResource HelpButtonStyle}" 
         Visibility="{TemplateBinding Property=ShowHelpButton, 
                Converter={StaticResource BoolToVisConverter}}" /> 
       </Grid> 

       <AdornerDecorator Grid.Row="1"> 
        <ContentPresenter x:Name="WindowContent" /> 
       </AdornerDecorator> 
       </Grid> 
      </Border> 
     </ControlTemplate> 
    </Setter.Value> 
    </Setter> 

最后,这里就是我如何使用它:

<abstractClasses:MainWindowFrame 
x:Class="Utils.UI.NewFeaturesDialog" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:abstractClasses="clr-namespace:Utils.AbstractClasses" 
xmlns:ui="clr-namespace:Utils.UI" 
xmlns:utilResx="clr-namespace:Utils.Resources" 
Width="775" 
DataContext="{Binding RelativeSource={RelativeSource Self}}" 
ShowHelpButton="False" 
SizeToContent="Height" 
Style="{DynamicResource ResourceKey=MainWindowStyle}"> 

<Window.Resources> 
    <ResourceDictionary> 
     <ResourceDictionary.MergedDictionaries> 
     <ResourceDictionary Source="/Utils;component/WPFStyles/Styles.xaml"/> 
    </ResourceDictionary.MergedDictionaries> 
    </ResourceDictionary> 
</Window.Resources> 
</abstractClasses:MainWindowFrame> 

我似乎尝试了一切。我已经添加了所有FrameworkPropertyMetadataOptions这样做:

FrameworkPropertyMetadataOptions.AffectsArrange | 

FrameworkPropertyMetadataOptions.AffectsMeasure | 

FrameworkPropertyMetadataOptions.AffectsRender | 

FrameworkPropertyMetadataOptions.AffectsParentMeasure | 

FrameworkPropertyMetadataOptions.AffectsParentArrange 

我也添加了一个回调无济于事。我甚至尝试重新启动Visual Studio 2015.我开始认为这只是一个VS错误,但我希望有人对发生了什么有一些想法。谢谢你的帮助!

+0

尝试在控件模板代替templatebinding使用触发器,看是否有利于 – Liero

更新答案

它看起来像它的一个已知的设计时的bug;对于子类/派生窗口对象 该报告的bug,似乎是与此相关的问题:WPF designer not showing content assigned to custom DependencyProperty

我们不能在设计器中创建窗口的设计实例,所以我们有一个代理类型我们自己的替代。

所以如果设计者不能创建派生窗口类型的实例;绑定(TemplateBinding)逻辑将在设计时失败。

因为它是不容易提供后备值TemplateBinding,你也许可以使用这个approach提供的默认值作为设计时行为。

+1

这与DataContext无关。 TemplateBinding正是这个 – Liero

+0

同意。刚刚通过您的代码;我错过了模板绑定。我会更新我的答案。 – Ada

+0

答复已更新。 – Ada

对不起,我不能重新创建你的问题。

我通常以更简单但仍然复杂的方式去。我把ViewModel放在另一个程序集中,所以我没有诱惑从视图中引用它。 +为了使所有样式都可调整,我将模板放入Generic.xaml中,并在另一个字典中重写样式,该样式在App.xaml中的Generic后加载 以下是我如何操作的方法。

MyWindow.xaml:

<Window x:Class="Sandbox.MyWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:local="clr-namespace:Sandbox" 
    xmlns:l="clr-namespace:ProjectLibrary;assembly=ProjectLibrary" 
    mc:Ignorable="d" d:DataContext="{DynamicResource DesignViewModel}" 
    Title="MyWindow" Height="300" Width="300"> 
<Window.Resources> 
    <l:MyViewModel x:Key="DesignViewModel" SomeButtonVisibility="Collapsed"/> 
</Window.Resources> 
<StackPanel> 
    <TextBlock Text="{Binding SomeText}"/> 
    <Button HorizontalAlignment="Center" VerticalAlignment="Center" Content="1 Button"/> 
    <Button Visibility="{Binding SomeButtonVisibility}" HorizontalAlignment="Center" VerticalAlignment="Center" Content="2 Button"/> 
    <Button HorizontalAlignment="Center" VerticalAlignment="Center" Content="3 Button"/> 
</StackPanel> 

在App.xaml中我删除了的StartupUri来处理它在App.xaml.cs:

using ProjectLibrary; 
using System.Windows; 

namespace Sandbox { 
public partial class App : Application { 
    MyWindow w; 
    MyViewModel vm; 

    public App() { 
     w = new MyWindow(); 
     //You also can pass Action to open new window of some sort here 
     //or other things, that VM can't have access to 
     vm = new MyViewModel(true); 
     w.DataContext = vm; 

     w.Show(); 
    } 
    } 
} 

MyViewModel:

using System.Windows; 

namespace ProjectLibrary 
{ 
public class MyViewModel : Notifiable 
{ 
    public MyViewModel() :this(false) { 
    } 

    public MyViewModel(bool Execute) { 
     if (Execute) { 
      SomeText = "Execution data"; 
     } else { 
      SomeText = "Design Data"; 
     } 
     SomeButtonVisibility = Visibility.Visible; 
    } 

    private string _someText; 
    public string SomeText { get { return _someText; } set { _someText = value; RaisePropertyChanged("SomeText"); } } 

    private Visibility _someButtonVisibility; 
    public Visibility SomeButtonVisibility { get { return _someButtonVisibility; } set { _someButtonVisibility = value; RaisePropertyChanged("SomeButtonVisibility"); } } 
} 
} 

Notifiable.cs:

using System.ComponentModel; 

namespace PTR.PTRLib.Common { 
public class Notifiable : INotifyPropertyChanged { 
    public event PropertyChangedEventHandler PropertyChanged; 
    protected void RaisePropertyChanged(string propertyName) { 
     // take a copy to prevent thread issues 
     PropertyChangedEventHandler handler = PropertyChanged; 
     if (handler != null) { 
      handler(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 
} 

的App.xaml:

<Application x:Class="Sandbox.App" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:local="clr-namespace:Sandbox"> 
<Application.Resources> 
    <ResourceDictionary> 
     <ResourceDictionary.MergedDictionaries> 
      <ResourceDictionary Source="Themes/Generic.xaml"/> <!-- Default Styles --> 
      <ResourceDictionary Source="Themes/StyleRes.xaml"/> <!-- ColorTemplates --> 
     </ResourceDictionary.MergedDictionaries> 
    </ResourceDictionary> 
</Application.Resources> 

模板/ Generic.xaml:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
       xmlns:local="clr-namespace:Sandbox"> 
<Style TargetType="{x:Type local:MyWindow}"> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="{x:Type Window}"> 
       <Grid> 
        <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}"> 
         <AdornerDecorator> 
          <ContentPresenter/> 
         </AdornerDecorator> 
        </Border> 
       </Grid> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
    <Style.Triggers> 
     <Trigger Property="ResizeMode" Value="CanResizeWithGrip"> 
      <Setter Property="Template" Value="{StaticResource WindowTemplateKey}"/> 
     </Trigger> 
    </Style.Triggers> 
</Style> 

主题/ StyleRes。XAML:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
       xmlns:local="clr-namespace:Sandbox"> 

<Style TargetType="{x:Type local:MyWindow}"> 
    <Setter Property="Foreground" Value="Red"/> 
    <Setter Property="Background" Value="LightBlue"/> 
</Style> 
<Style TargetType="{x:Type Button}"> 
    <Setter Property="Foreground" Value="Red"/> 
    <Setter Property="Background" Value="LightBlue"/> 
</Style> 

我不是在WPF一个专业的,但是这是我在1.5年编程数据库+ WPF界面(好一个)的过程中的经验教训。

+0

噢......至于沙拉达普拉Gururaj说,这是一个已知的bug。现在我记得我曾经处理过类似的事情,但没有找到解决办法。于是,我开始做在用户控件的一切,但现在我意识到,你可以用我的方式很容易做到CustomControls。您可以将每个控件的原型制作为UserControl,然后复制/粘贴并创建一个CustomControl。稍后可以轻松制作模板并重新使用您的控件。 –

+0

感谢您的回复!这可能是一种解决方法,但唯一的问题是所有设计MyWindow的代码都必须在.cs文件中完成,因为我想在包含xaml代码的另一个类中继承MyWindow(不允许你继承在另一个xaml文件中使用xaml定义的类)。我真的不想在cs文件中创建所有的UI代码。 –

我知道这可能是一个简单的答案....但是我想这个问题,因为它只是在设计时,可能是由于在设计数据方面的问题。你有没有尝试d:DataContext?

d:DataContext ="{d:DesignInstance {x:Type nameSpace:ViewModel}, IsDesignTimeCreatable=True}" 

https://www.codeproject.com/tips/879109/using-design-time-databinding-while-developing-a-w