Dependency Property Not Updating Visual Studio Designer

倖福魔咒の 提交于 2021-01-29 03:50:22

问题


I've created a style for a new WPF Window class and have some dependency properties on there. The one to note is

ShowHelpButton

This is supposed to toggle the visibility of the Help button on the window. The code works fine in runtime, but I cannot get it to update the UI in the design view.

Here's the class:

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)));
  }

Here's the Style:

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

And finally, here's how I'm using it:

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

I've seemingly tried everything. I've added all the FrameworkPropertyMetadataOptions by doing this:

FrameworkPropertyMetadataOptions.AffectsArrange |

FrameworkPropertyMetadataOptions.AffectsMeasure |

FrameworkPropertyMetadataOptions.AffectsRender |

FrameworkPropertyMetadataOptions.AffectsParentMeasure |

FrameworkPropertyMetadataOptions.AffectsParentArrange

I've also added a callback to no avail. I've even tried restarting Visual Studio 2015. I'm starting to think it's just a VS bug, but I'm hoping someone has some idea of what's going on. Thanks for any help!


回答1:


Updated answer

It looks like its a known design-time bug; for subclassed/derived Window objects This reported bug seems to be related to this issue: WPF designer not showing content assigned to custom DependencyProperty

We cannot create a design instance of Window within the designer so we substitute with a proxy type of our own.

So if the designer can't create an instance of derived window type; the binding (TemplateBinding) logic will fail during design-time.

As it is not easy to provide fallback values to TemplateBinding, you can maybe use this approach to provide default values to act as design-time behavior.




回答2:


Sorry I can't recreate your problem.

I go usually in a simpler but still complicated way. I put ViewModel in another assembly, so I would have no temptation to reference it from view. + To make everything stylable, I put Templates into Generic.xaml and override Styles in another dictionary, that is loaded after Generic in App.xaml Here is how I do things.

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>

In App.xaml I remove StartupURI to handle it in 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>

Templates/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>

Themes/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>

I'm not a professional in WPF, but this is what I learned in 1.5 year course of programming a database + wpf interface (nice one).




回答3:


I know this may be a short answer.... But I am thinking the issue, since it is only at design time, might be due to a data context issues in the designer. Have you tried 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



来源:https://stackoverflow.com/questions/43429308/dependency-property-not-updating-visual-studio-designer

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!