Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# WPF自定义控件在视图模型子属性更改时重新渲染_C#_.net_Wpf_Data Binding_Custom Controls - Fatal编程技术网

C# WPF自定义控件在视图模型子属性更改时重新渲染

C# WPF自定义控件在视图模型子属性更改时重新渲染,c#,.net,wpf,data-binding,custom-controls,C#,.net,Wpf,Data Binding,Custom Controls,WPF自定义控件能否跟踪视图模型子属性的更改以自动重新渲染自身 假设我有一个具有两个属性的模型: public class FullName : ViewModel { string _first; string _last; public string First { get { return _first; } set { _first = value; Rais

WPF自定义控件能否跟踪视图模型子属性的更改以自动重新渲染自身

假设我有一个具有两个属性的模型:

public class FullName : ViewModel
{
    string _first;
    string _last;

    public string First
    {
        get { return _first; }
        set
        {
            _first = value;
            RaisePropertyChanged();
        }
    }

    public string Last
    {
        get { return _last; }
        set
        {
            _last = value;
            RaisePropertyChanged();
        }
    }
}
其中
ViewModel
为:

public abstract class ViewModel : INotifyPropertyChanged
{
    protected void RaisePropertyChanged([CallerMemberName] string propertyName = null) =>
        OnPropertyChanged(new PropertyChangedEventArgs(propertyName));

    protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) =>
        PropertyChanged?.Invoke(this, e);

    public event PropertyChangedEventHandler PropertyChanged;
}
我希望WPF自定义控件(
AffectsRender
,no
子属性donotaffectrender
)上有一个依赖项属性来引用模型,以便控件在
First
Last
属性更改时自动重新渲染:

public class Tag : Control
{
    public static readonly DependencyProperty FullNameProperty =
        DependencyProperty.Register("FullName", typeof(FullName), typeof(Tag),
            new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender));

    public FullName FullName
    {
        get { return (FullName)GetValue(FullNameProperty); }
        set { SetValue(FullNameProperty, value); }
    }

    protected override void OnRender(DrawingContext drawingContext)
    {
        base.OnRender(drawingContext);
        if (FullName == null)
            return;

        FontFamily courier = new FontFamily("Courier New");
        Typeface courierTypeface = new Typeface(courier, FontStyles.Normal, FontWeights.Normal, FontStretches.Normal);
        FormattedText ft2 = new FormattedText(FullName.First + " " + FullName.Last,
                                             CultureInfo.CurrentCulture,
                                             FlowDirection.LeftToRight,
                                             courierTypeface,
                                             14.0,
                                             Brushes.Black);

        drawingContext.DrawText(ft2, new Point());
    }
}
下面是测试它的代码段:

<Window x:Class="WpfApplication3.MainWindow"
    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:WpfApplication3"
    mc:Ignorable="d"
    Title="MainWindow" Height="139.9" Width="249.514">
  <StackPanel>
    <StackPanel.DataContext>
        <local:FullName>
            <local:FullName.First>John</local:FullName.First>
            <local:FullName.Last>Doe</local:FullName.Last>
        </local:FullName>
    </StackPanel.DataContext>
    <local:Tag FullName="{Binding}" Height="20"/>
    <TextBox Text="{Binding First, UpdateSourceTrigger=PropertyChanged}"/>
    <TextBox Text="{Binding Last, UpdateSourceTrigger=PropertyChanged}"/>
  </StackPanel>
</Window>

约翰
雌鹿

不幸的是,它不起作用–更改不会传播到自定义控件。这能有效地完成吗?那么这个
子属性donotaffectrender
是关于什么的呢?

要让它起作用,你的
全名
类必须是一个
可自由化的
,你的
第一个
最后一个
属性必须是依赖属性

您可以查看
DependencyObject

internal void NotifySubPropertyChange(DependencyProperty dp)
{
    InvalidateSubProperty(dp);

    // if the target is a Freezable, call FireChanged to kick off
    // notifications to the Freezable's parent chain.
    Freezable freezable = this as Freezable;
    if (freezable != null)
    {
        freezable.FireChanged();
    }
}
此机制最初不用于观察绑定视图模型的子属性。通过观察
Freezable
s`属性并触发更改其属性和子属性的适当操作,它有助于简化
FrameworkElement
的测量、排列和渲染


你可以找到一篇很好的博文,解释WPF中保留的图形系统是如何工作的,以及如何使用你感兴趣的功能。

@nkoniishvt实际上,请看一下
Tag.OnRender
,它绘制了
FullName.First+“”+FullName.Last
。我需要的是完全“所有者绘制”的图表组件(不涉及模板或继承),以显示可动态更新的视图模型对象图的内容。我得到的印象是,控件跟踪模型子属性的更改而不通过
子属性donotaffectrender
进行显式抑制,但这对我不起作用。当我的none-
Freezable
类型的属性更改时,是否有正式的方法调用
notifysubpertychange
?我使用过代码反射,但它既慢又危险…@DmitryNogin,恐怕没有办法做到这一点。要通过反射加速方法调用,可以缓存
委托
,如中所述。然而,依赖.NET Framework的内部方法并不是编写可维护和可靠代码的好方法,所以我不建议这样做。