【问题标题】:Dependency Property Not Updating Visual Studio Designer依赖属性未更新 Visual Studio 设计器
【发布时间】:2017-04-15 17:47:48
【问题描述】:

我已经为一个新的 WPF Window 类创建了一个样式,并且在那里有一些依赖属性。需要注意的是

显示帮助按钮

这应该切换窗口上帮助按钮的可见性。该代码在运行时运行良好,但我无法让它在设计视图中更新 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 错误,但我希望有人知道发生了什么。感谢您的帮助!

【问题讨论】:

  • 尝试在controltemplate中使用trigger代替templatebinding,看看是否有帮助

标签: c# wpf visual-studio-2015 dependency-properties


【解决方案1】:

更新答案

它看起来像是一个已知的设计时错误;对于子类/派生的 Window 对象 这个报告的错误似乎与这个问题有关:WPF designer not showing content assigned to custom DependencyProperty

我们无法在设计器中创建 Window 的设计实例,因此我们用我们自己的代理类型替换。

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

由于向 TemplateBinding 提供后备值并不容易,您可以使用此 approach 提供默认值以充当设计时行为。

【讨论】:

  • 这与DataContext无关。 TemplateBinding 正是为此而生的
  • 同意。刚刚再次浏览了您的代码;我错过了模板绑定。我会更新我的答案。
  • 我就是这么想的(也害怕哈哈)。感谢您确认这是一个 VS 错误。我希望这实际上不是一条评论所暗示的预期设计。也许有一天它会得到修复。
【解决方案2】:

抱歉,我无法重现您的问题。

我通常以更简单但仍然复杂的方式进行。我将 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 界面编程课程中学到的(很好)。

【讨论】:

  • Aww... 正如 Sharada Gururaj 所说,这是一个已知的错误。现在我记得我以前处理过类似的事情,但没有找到解决方案。所以我开始在用户控件中做所有事情,但现在我意识到你可以用我的模式轻松地做 CustomControls。您可以将每个控件原型化为 UserControl,然后复制/粘贴并创建一个 CustomControl。以后制作模板和重用控件会很容易。
  • 感谢您的回复!这可能是一种解决方法,但唯一的问题是设计 MyWindow 的所有代码都必须在 .cs 文件中完成,因为我想在另一个包含 xaml 代码的类中继承 MyWindow(不允许继承在另一个 xaml 文件中使用 xaml 定义的类)。我真的不想在 cs 文件中创建我所有的 UI 代码。
【解决方案3】:

我知道这可能是一个简短的答案......但我在想这个问题,因为它只是在设计时,可能是由于设计器中的数据上下文问题。你试过 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多