[{"data":1,"prerenderedAt":1187},["ShallowReactive",2],{"page-\u002Fcsharp\u002Fwpf\u002F继承contentcontrol来管理内容的加载":3},{"id":4,"title":5,"body":6,"description":351,"extension":1181,"meta":1182,"navigation":1065,"path":1183,"seo":1184,"stem":1185,"__hash__":1186},"content\u002Fcsharp\u002FWPF\u002F继承ContentControl来管理内容的加载.md","继承ContentControl来管理内容的加载",{"type":7,"value":8,"toc":1177},"minimark",[9,14,27,30,39,46,53,60,67,74,81,83,86,93,100,107,114,121,129,132,300,339,342,345,452,455,458,851,854,869,872,875,904,907,951,967,974,977,1039,1042,1048,1051,1173],[10,11,13],"h3",{"id":12},"contentcontrol","ContentControl",[15,16,17,18,22,23,26],"p",{},"WPF的ContentControl是WPF控件的一种特殊形式，用于",[19,20,21],"strong",{},"存储用户输入或从任何其他数据源读取的内容","。内容控件",[19,24,25],{},"只能包含一个子元素","。这与包含多个子元素的布局控件（如Grid、WrapPanel和StackPanel控件）不同。",[15,28,29],{},"我们通过微软的资料就可以去看见它的定义和用途：\n继承",[15,31,32],{},[33,34,38],"a",{"href":35,"rel":36},"https:\u002F\u002Flearn.microsoft.com\u002Fzh-cn\u002Fdotnet\u002Fapi\u002Fsystem.object?view=windowsdesktop-8.0",[37],"nofollow","Object",[15,40,41],{},[33,42,45],{"href":43,"rel":44},"https:\u002F\u002Flearn.microsoft.com\u002Fzh-cn\u002Fdotnet\u002Fapi\u002Fsystem.windows.threading.dispatcherobject?view=windowsdesktop-8.0",[37],"DispatcherObject",[15,47,48],{},[33,49,52],{"href":50,"rel":51},"https:\u002F\u002Flearn.microsoft.com\u002Fzh-cn\u002Fdotnet\u002Fapi\u002Fsystem.windows.dependencyobject?view=windowsdesktop-8.0",[37],"DependencyObject",[15,54,55],{},[33,56,59],{"href":57,"rel":58},"https:\u002F\u002Flearn.microsoft.com\u002Fzh-cn\u002Fdotnet\u002Fapi\u002Fsystem.windows.media.visual?view=windowsdesktop-8.0",[37],"Visual",[15,61,62],{},[33,63,66],{"href":64,"rel":65},"https:\u002F\u002Flearn.microsoft.com\u002Fzh-cn\u002Fdotnet\u002Fapi\u002Fsystem.windows.uielement?view=windowsdesktop-8.0",[37],"UIElement",[15,68,69],{},[33,70,73],{"href":71,"rel":72},"https:\u002F\u002Flearn.microsoft.com\u002Fzh-cn\u002Fdotnet\u002Fapi\u002Fsystem.windows.frameworkelement?view=windowsdesktop-8.0",[37],"FrameworkElement",[15,75,76],{},[33,77,80],{"href":78,"rel":79},"https:\u002F\u002Flearn.microsoft.com\u002Fzh-cn\u002Fdotnet\u002Fapi\u002Fsystem.windows.controls.control?view=windowsdesktop-8.0",[37],"Control",[15,82,13],{},[15,84,85],{},"派生",[15,87,88],{},[33,89,92],{"href":90,"rel":91},"https:\u002F\u002Flearn.microsoft.com\u002Fzh-cn\u002Fdotnet\u002Fapi\u002Fsystem.activities.presentation.view.expressiontextbox?view=windowsdesktop-8.0",[37],"System.Activities.Presentation.View.ExpressionTextBox",[15,94,95],{},[33,96,99],{"href":97,"rel":98},"https:\u002F\u002Flearn.microsoft.com\u002Fzh-cn\u002Fdotnet\u002Fapi\u002Fsystem.activities.presentation.view.typepresenter?view=windowsdesktop-8.0",[37],"System.Activities.Presentation.View.TypePresenter",[15,101,102],{},[33,103,106],{"href":104,"rel":105},"https:\u002F\u002Flearn.microsoft.com\u002Fzh-cn\u002Fdotnet\u002Fapi\u002Fsystem.activities.presentation.workflowelementdialog?view=windowsdesktop-8.0",[37],"System.Activities.Presentation.WorkflowElementDialog",[15,108,109],{},[33,110,113],{"href":111,"rel":112},"https:\u002F\u002Flearn.microsoft.com\u002Fzh-cn\u002Fdotnet\u002Fapi\u002Fsystem.activities.presentation.workflowitempresenter?view=windowsdesktop-8.0",[37],"System.Activities.Presentation.WorkflowItemPresenter",[15,115,116],{},[33,117,120],{"href":118,"rel":119},"https:\u002F\u002Flearn.microsoft.com\u002Fzh-cn\u002Fdotnet\u002Fapi\u002Fsystem.activities.presentation.workflowitemspresenter?view=windowsdesktop-8.0",[37],"System.Activities.Presentation.WorkflowItemsPresenter",[15,122,123],{},[33,124,128],{"href":125,"rel":126,"title":127},"https:\u002F\u002Flearn.microsoft.com\u002Fzh-cn\u002Fdotnet\u002Fapi\u002Fsystem.windows.controls.contentcontrol?view=windowsdesktop-8.0#",[37],"显示所有派生类","更多…",[15,130,131],{},"几乎所有可以使用Content的控件都是继承于它的，比如：",[133,134,135,144,151,158,165,177,185,193,201,209,221,248,256,264,271,278,285],"ul",{},[136,137,138],"li",{},[19,139,140],{},[141,142,143],"code",{},"Button",[136,145,146],{},[19,147,148],{},[141,149,150],{},"CheckBox",[136,152,153],{},[19,154,155],{},[141,156,157],{},"RadioButton",[136,159,160],{},[19,161,162],{},[141,163,164],{},"ToggleButton",[136,166,167,172,173,176],{},[19,168,169],{},[141,170,171],{},"RepeatButton","\n还有",[19,174,175],{},"容器与窗口","类：",[136,178,179,184],{},[19,180,181],{},[141,182,183],{},"Window"," (WPF 中的顶级窗口)",[136,186,187,192],{},[19,188,189],{},[141,190,191],{},"UserControl"," (用户自定义控件)",[136,194,195,200],{},[19,196,197],{},[141,198,199],{},"ScrollViewer"," (滚动视图)",[136,202,203,208],{},[19,204,205],{},[141,206,207],{},"GroupBox"," (带标题的边框容器)",[136,210,211,216,217,220],{},[19,212,213],{},[141,214,215],{},"Frame"," (用于导航的框架)\n或者说",[19,218,219],{},"数据显示与修饰类","：",[136,222,223,228,229,232,233,232,236,238,239,241,242,244,245,247],{},[19,224,225],{},[141,226,227],{},"Label"," (注意：",[141,230,231],{},"TextBlock"," ",[19,234,235],{},"不是",[141,237,13],{},"，但 ",[141,240,227],{}," 是。区别在于 ",[141,243,227],{}," 可以放图片，",[141,246,231],{}," 只能放文字)",[136,249,250,255],{},[19,251,252],{},[141,253,254],{},"ToolTip"," (鼠标悬停提示)",[136,257,258,263],{},[19,259,260],{},[141,261,262],{},"StatusBarItem","\n列表项：",[136,265,266],{},[19,267,268],{},[141,269,270],{},"ListBoxItem",[136,272,273],{},[19,274,275],{},[141,276,277],{},"ComboBoxItem",[136,279,280],{},[19,281,282],{},[141,283,284],{},"TabItem",[136,286,287,292,293,295,296,299],{},[19,288,289],{},[141,290,291],{},"TreeViewItem"," (它比较特殊，既是 ",[141,294,13],{}," 又是 ",[141,297,298],{},"ItemsControl","，因为它有 Header 也有子节点)",[15,301,302,306,307,312,313,316,317,322,323,328,329,333,334,338],{},[33,303,13],{"href":304,"rel":305},"https:\u002F\u002Flearn.microsoft.com\u002Fzh-cn\u002Fdotnet\u002Fapi\u002Fsystem.windows.controls.contentcontrol?view=windowsdesktop-8.0",[37],"可以包含任何类型的公共语言运行时对象 (，例如字符串或",[33,308,311],{"href":309,"rel":310},"https:\u002F\u002Flearn.microsoft.com\u002Fzh-cn\u002Fdotnet\u002Fapi\u002Fsystem.datetime?view=windowsdesktop-8.0",[37],"DateTime","对象) 或",[33,314,66],{"href":64,"rel":315},[37],"对象 (，如 ",[33,318,321],{"href":319,"rel":320},"https:\u002F\u002Flearn.microsoft.com\u002Fzh-cn\u002Fdotnet\u002Fapi\u002Fsystem.windows.shapes.rectangle?view=windowsdesktop-8.0",[37],"Rectangle"," 或 ",[33,324,327],{"href":325,"rel":326},"https:\u002F\u002Flearn.microsoft.com\u002Fzh-cn\u002Fdotnet\u002Fapi\u002Fsystem.windows.controls.panel?view=windowsdesktop-8.0",[37],"Panel",") 。 这使你能够将丰富内容添加到 控件，例如 ",[33,330,143],{"href":331,"rel":332},"https:\u002F\u002Flearn.microsoft.com\u002Fzh-cn\u002Fdotnet\u002Fapi\u002Fsystem.windows.controls.button?view=windowsdesktop-8.0",[37]," 和 ",[33,335,150],{"href":336,"rel":337},"https:\u002F\u002Flearn.microsoft.com\u002Fzh-cn\u002Fdotnet\u002Fapi\u002Fsystem.windows.controls.checkbox?view=windowsdesktop-8.0",[37],"。",[15,340,341],{},"与他相对的就是条目控件ItemsControl，它则是可以容纳N个控件，我们可以控制子组件的加载周期，ItemsControl有一个核心机制叫做容器生成器，数据进来的时候，为每个数据包裹一个容器，例如ListBoxItems或者默认ContentPresenter，我们就可以监听这个容器的Loaded和Unloaded事件。",[15,343,344],{},"实现子组件加载的动画，比如说左侧滑入，我们可以修改ItemsControl的ItemContainerStyle来实现。",[346,347,352],"pre",{"className":348,"code":349,"language":350,"meta":351,"style":351},"language-xml shiki shiki-themes github-light github-dark","\u003CItemsControl ItemsSource=\"{Binding MyItems}\">\n    \u003CItemsControl.ItemContainerStyle>\n        \u003CStyle TargetType=\"ContentPresenter\">\n            \u003CStyle.Triggers>\n                \u003CEventTrigger RoutedEvent=\"Loaded\">\n                    \u003CBeginStoryboard>\n                        \u003CStoryboard>\n                            \u003CDoubleAnimation Storyboard.TargetProperty=\"Opacity\" \n                                             From=\"0\" To=\"1\" Duration=\"0:0:0.5\"\u002F>\n                        \u003C\u002FStoryboard>\n                    \u003C\u002FBeginStoryboard>\n                \u003C\u002FEventTrigger>\n            \u003C\u002FStyle.Triggers>\n        \u003C\u002FStyle>\n    \u003C\u002FItemsControl.ItemContainerStyle>\n\u003C\u002FItemsControl>\n","xml","",[141,353,354,362,368,374,380,386,392,398,404,410,416,422,428,434,440,446],{"__ignoreMap":351},[355,356,359],"span",{"class":357,"line":358},"line",1,[355,360,361],{},"\u003CItemsControl ItemsSource=\"{Binding MyItems}\">\n",[355,363,365],{"class":357,"line":364},2,[355,366,367],{},"    \u003CItemsControl.ItemContainerStyle>\n",[355,369,371],{"class":357,"line":370},3,[355,372,373],{},"        \u003CStyle TargetType=\"ContentPresenter\">\n",[355,375,377],{"class":357,"line":376},4,[355,378,379],{},"            \u003CStyle.Triggers>\n",[355,381,383],{"class":357,"line":382},5,[355,384,385],{},"                \u003CEventTrigger RoutedEvent=\"Loaded\">\n",[355,387,389],{"class":357,"line":388},6,[355,390,391],{},"                    \u003CBeginStoryboard>\n",[355,393,395],{"class":357,"line":394},7,[355,396,397],{},"                        \u003CStoryboard>\n",[355,399,401],{"class":357,"line":400},8,[355,402,403],{},"                            \u003CDoubleAnimation Storyboard.TargetProperty=\"Opacity\" \n",[355,405,407],{"class":357,"line":406},9,[355,408,409],{},"                                             From=\"0\" To=\"1\" Duration=\"0:0:0.5\"\u002F>\n",[355,411,413],{"class":357,"line":412},10,[355,414,415],{},"                        \u003C\u002FStoryboard>\n",[355,417,419],{"class":357,"line":418},11,[355,420,421],{},"                    \u003C\u002FBeginStoryboard>\n",[355,423,425],{"class":357,"line":424},12,[355,426,427],{},"                \u003C\u002FEventTrigger>\n",[355,429,431],{"class":357,"line":430},13,[355,432,433],{},"            \u003C\u002FStyle.Triggers>\n",[355,435,437],{"class":357,"line":436},14,[355,438,439],{},"        \u003C\u002FStyle>\n",[355,441,443],{"class":357,"line":442},15,[355,444,445],{},"    \u003C\u002FItemsControl.ItemContainerStyle>\n",[355,447,449],{"class":357,"line":448},16,[355,450,451],{},"\u003C\u002FItemsControl>\n",[15,453,454],{},"这个就不细讲了，我们可以在另外的笔记里面细讲。",[10,456,457],{"id":457},"主要内容",[346,459,463],{"className":460,"code":461,"language":462,"meta":351,"style":351},"language-cs shiki shiki-themes github-light github-dark","using System.Windows;  \nusing System.Windows.Controls;  \nusing System.Windows.Media;  \nusing System.Windows.Media.Animation;  \n  \nnamespace TheTestSolutionForWPF.Views;  \npublic class ContentWrapper : ContentControl  \n{  \n    public static readonly DependencyProperty IsActiveProperty = DependencyProperty.Register(  \n        nameof(IsActive), typeof(bool), typeof(ContentWrapper), new PropertyMetadata(true, OnIsActiveChanged));  \n        \n    public bool IsActive  \n    {  \n        get => (bool)GetValue(IsActiveProperty);  \n        set => SetValue(IsActiveProperty, value);  \n    }    \n    public ContentWrapper()   \n    {  \n        this.Background = Brushes.Transparent;  \n        var group = new TransformGroup();  \n        group.Children.Add(new ScaleTransform(1, 1));  \n        group.Children.Add(new TranslateTransform(0, 0));  \n        this.RenderTransform = group;  \n        this.RenderTransformOrigin = new Point(0.5, 0.5); \u002F\u002F 从中心缩放  \n    }  \n    \n    private static void OnIsActiveChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)  \n    {        var control = (ContentWrapper)d;  \n        bool newValue = (bool)e.NewValue;  \n            if (newValue)  \n        {            control.AnimateIn();  \n        }        else  \n        {  \n            control.AnimateOut();  \n        }    }    private void AnimateIn()  \n        {            this.Visibility = Visibility.Visible;  \n            var springEase = new ElasticEase   \n{   \nOscillations = 1,   \nSpringiness = 5   \n};  \n            var scaleAnim = new DoubleAnimation(0.8, 1.0, TimeSpan.FromSeconds(0.8))  \n            {                EasingFunction = springEase  \n            };  \n            var opacityAnim = new DoubleAnimation(0, 1, TimeSpan.FromSeconds(0.3));  \n            var transformGroup = this.RenderTransform as TransformGroup;  \n            var scaleTransform = transformGroup.Children[0] as ScaleTransform;  \n            scaleTransform.BeginAnimation(ScaleTransform.ScaleXProperty, scaleAnim);  \n            scaleTransform.BeginAnimation(ScaleTransform.ScaleYProperty, scaleAnim);  \n            this.BeginAnimation(UIElement.OpacityProperty, opacityAnim);  \n        }        private void AnimateOut()  \n        {            var smoothEase = new QuadraticEase { EasingMode = EasingMode.EaseOut };  \n            var scaleAnim = new DoubleAnimation(1.0, 0.9, TimeSpan.FromSeconds(0.3))  \n            {                EasingFunction = smoothEase  \n            };  \n            var opacityAnim = new DoubleAnimation(1, 0, TimeSpan.FromSeconds(0.2));  \n            opacityAnim.Completed += (s, e) =>   \n            {  \n                if (!this.IsActive)   \n                {  \n                    this.Visibility = Visibility.Collapsed;  \n                }            };            \n                var transformGroup = this.RenderTransform as TransformGroup;  \n            var scaleTransform = transformGroup.Children[0] as ScaleTransform;  \n            scaleTransform.BeginAnimation(ScaleTransform.ScaleXProperty, scaleAnim);  \n            scaleTransform.BeginAnimation(ScaleTransform.ScaleYProperty, scaleAnim);  \n            this.BeginAnimation(UIElement.OpacityProperty, opacityAnim);  \n        }}\n","cs",[141,464,465,470,475,480,485,490,495,500,505,510,515,520,525,530,535,540,545,551,556,562,568,574,580,586,592,598,604,610,616,622,628,634,640,646,652,658,664,670,676,682,688,694,700,706,712,718,724,730,736,742,748,754,760,766,772,777,783,789,795,801,807,813,819,825,830,835,840,845],{"__ignoreMap":351},[355,466,467],{"class":357,"line":358},[355,468,469],{},"using System.Windows;  \n",[355,471,472],{"class":357,"line":364},[355,473,474],{},"using System.Windows.Controls;  \n",[355,476,477],{"class":357,"line":370},[355,478,479],{},"using System.Windows.Media;  \n",[355,481,482],{"class":357,"line":376},[355,483,484],{},"using System.Windows.Media.Animation;  \n",[355,486,487],{"class":357,"line":382},[355,488,489],{},"  \n",[355,491,492],{"class":357,"line":388},[355,493,494],{},"namespace TheTestSolutionForWPF.Views;  \n",[355,496,497],{"class":357,"line":394},[355,498,499],{},"public class ContentWrapper : ContentControl  \n",[355,501,502],{"class":357,"line":400},[355,503,504],{},"{  \n",[355,506,507],{"class":357,"line":406},[355,508,509],{},"    public static readonly DependencyProperty IsActiveProperty = DependencyProperty.Register(  \n",[355,511,512],{"class":357,"line":412},[355,513,514],{},"        nameof(IsActive), typeof(bool), typeof(ContentWrapper), new PropertyMetadata(true, OnIsActiveChanged));  \n",[355,516,517],{"class":357,"line":418},[355,518,519],{},"        \n",[355,521,522],{"class":357,"line":424},[355,523,524],{},"    public bool IsActive  \n",[355,526,527],{"class":357,"line":430},[355,528,529],{},"    {  \n",[355,531,532],{"class":357,"line":436},[355,533,534],{},"        get => (bool)GetValue(IsActiveProperty);  \n",[355,536,537],{"class":357,"line":442},[355,538,539],{},"        set => SetValue(IsActiveProperty, value);  \n",[355,541,542],{"class":357,"line":448},[355,543,544],{},"    }    \n",[355,546,548],{"class":357,"line":547},17,[355,549,550],{},"    public ContentWrapper()   \n",[355,552,554],{"class":357,"line":553},18,[355,555,529],{},[355,557,559],{"class":357,"line":558},19,[355,560,561],{},"        this.Background = Brushes.Transparent;  \n",[355,563,565],{"class":357,"line":564},20,[355,566,567],{},"        var group = new TransformGroup();  \n",[355,569,571],{"class":357,"line":570},21,[355,572,573],{},"        group.Children.Add(new ScaleTransform(1, 1));  \n",[355,575,577],{"class":357,"line":576},22,[355,578,579],{},"        group.Children.Add(new TranslateTransform(0, 0));  \n",[355,581,583],{"class":357,"line":582},23,[355,584,585],{},"        this.RenderTransform = group;  \n",[355,587,589],{"class":357,"line":588},24,[355,590,591],{},"        this.RenderTransformOrigin = new Point(0.5, 0.5); \u002F\u002F 从中心缩放  \n",[355,593,595],{"class":357,"line":594},25,[355,596,597],{},"    }  \n",[355,599,601],{"class":357,"line":600},26,[355,602,603],{},"    \n",[355,605,607],{"class":357,"line":606},27,[355,608,609],{},"    private static void OnIsActiveChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)  \n",[355,611,613],{"class":357,"line":612},28,[355,614,615],{},"    {        var control = (ContentWrapper)d;  \n",[355,617,619],{"class":357,"line":618},29,[355,620,621],{},"        bool newValue = (bool)e.NewValue;  \n",[355,623,625],{"class":357,"line":624},30,[355,626,627],{},"            if (newValue)  \n",[355,629,631],{"class":357,"line":630},31,[355,632,633],{},"        {            control.AnimateIn();  \n",[355,635,637],{"class":357,"line":636},32,[355,638,639],{},"        }        else  \n",[355,641,643],{"class":357,"line":642},33,[355,644,645],{},"        {  \n",[355,647,649],{"class":357,"line":648},34,[355,650,651],{},"            control.AnimateOut();  \n",[355,653,655],{"class":357,"line":654},35,[355,656,657],{},"        }    }    private void AnimateIn()  \n",[355,659,661],{"class":357,"line":660},36,[355,662,663],{},"        {            this.Visibility = Visibility.Visible;  \n",[355,665,667],{"class":357,"line":666},37,[355,668,669],{},"            var springEase = new ElasticEase   \n",[355,671,673],{"class":357,"line":672},38,[355,674,675],{},"{   \n",[355,677,679],{"class":357,"line":678},39,[355,680,681],{},"Oscillations = 1,   \n",[355,683,685],{"class":357,"line":684},40,[355,686,687],{},"Springiness = 5   \n",[355,689,691],{"class":357,"line":690},41,[355,692,693],{},"};  \n",[355,695,697],{"class":357,"line":696},42,[355,698,699],{},"            var scaleAnim = new DoubleAnimation(0.8, 1.0, TimeSpan.FromSeconds(0.8))  \n",[355,701,703],{"class":357,"line":702},43,[355,704,705],{},"            {                EasingFunction = springEase  \n",[355,707,709],{"class":357,"line":708},44,[355,710,711],{},"            };  \n",[355,713,715],{"class":357,"line":714},45,[355,716,717],{},"            var opacityAnim = new DoubleAnimation(0, 1, TimeSpan.FromSeconds(0.3));  \n",[355,719,721],{"class":357,"line":720},46,[355,722,723],{},"            var transformGroup = this.RenderTransform as TransformGroup;  \n",[355,725,727],{"class":357,"line":726},47,[355,728,729],{},"            var scaleTransform = transformGroup.Children[0] as ScaleTransform;  \n",[355,731,733],{"class":357,"line":732},48,[355,734,735],{},"            scaleTransform.BeginAnimation(ScaleTransform.ScaleXProperty, scaleAnim);  \n",[355,737,739],{"class":357,"line":738},49,[355,740,741],{},"            scaleTransform.BeginAnimation(ScaleTransform.ScaleYProperty, scaleAnim);  \n",[355,743,745],{"class":357,"line":744},50,[355,746,747],{},"            this.BeginAnimation(UIElement.OpacityProperty, opacityAnim);  \n",[355,749,751],{"class":357,"line":750},51,[355,752,753],{},"        }        private void AnimateOut()  \n",[355,755,757],{"class":357,"line":756},52,[355,758,759],{},"        {            var smoothEase = new QuadraticEase { EasingMode = EasingMode.EaseOut };  \n",[355,761,763],{"class":357,"line":762},53,[355,764,765],{},"            var scaleAnim = new DoubleAnimation(1.0, 0.9, TimeSpan.FromSeconds(0.3))  \n",[355,767,769],{"class":357,"line":768},54,[355,770,771],{},"            {                EasingFunction = smoothEase  \n",[355,773,775],{"class":357,"line":774},55,[355,776,711],{},[355,778,780],{"class":357,"line":779},56,[355,781,782],{},"            var opacityAnim = new DoubleAnimation(1, 0, TimeSpan.FromSeconds(0.2));  \n",[355,784,786],{"class":357,"line":785},57,[355,787,788],{},"            opacityAnim.Completed += (s, e) =>   \n",[355,790,792],{"class":357,"line":791},58,[355,793,794],{},"            {  \n",[355,796,798],{"class":357,"line":797},59,[355,799,800],{},"                if (!this.IsActive)   \n",[355,802,804],{"class":357,"line":803},60,[355,805,806],{},"                {  \n",[355,808,810],{"class":357,"line":809},61,[355,811,812],{},"                    this.Visibility = Visibility.Collapsed;  \n",[355,814,816],{"class":357,"line":815},62,[355,817,818],{},"                }            };            \n",[355,820,822],{"class":357,"line":821},63,[355,823,824],{},"                var transformGroup = this.RenderTransform as TransformGroup;  \n",[355,826,828],{"class":357,"line":827},64,[355,829,729],{},[355,831,833],{"class":357,"line":832},65,[355,834,735],{},[355,836,838],{"class":357,"line":837},66,[355,839,741],{},[355,841,843],{"class":357,"line":842},67,[355,844,747],{},[355,846,848],{"class":357,"line":847},68,[355,849,850],{},"        }}\n",[15,852,853],{},"上面的代码是行为封装在自定义控制内部的模式也就是：Logic-less XAML, Logic-rich Control\n是符合WPF\u002FAvalonia的高级开发习惯的。",[346,855,857],{"className":460,"code":856,"language":462,"meta":351,"style":351},"public static readonly DependencyProperty IsActiveProperty = DependencyProperty.Register(  \n    nameof(IsActive), typeof(bool), typeof(ContentWrapper), new PropertyMetadata(true, OnIsActiveChanged));\n",[141,858,859,864],{"__ignoreMap":351},[355,860,861],{"class":357,"line":358},[355,862,863],{},"public static readonly DependencyProperty IsActiveProperty = DependencyProperty.Register(  \n",[355,865,866],{"class":357,"line":364},[355,867,868],{},"    nameof(IsActive), typeof(bool), typeof(ContentWrapper), new PropertyMetadata(true, OnIsActiveChanged));\n",[15,870,871],{},"这里是我们注册依赖属性的地方，我们注册了一个叫做IsActive的属性，类型是Bool，属于一个叫做ContentWrapper的类，这个属性默认为True，最后面部分我们注册了一个回调函数，这个是属性的监听器，当IsActive从True变为了Flase的时候或者反之，他就会调用这个静态方法。",[15,873,874],{},"我们的AnimateIn和AnimateOut就是靠这个钩子来触发的。",[346,876,878],{"className":460,"code":877,"language":462,"meta":351,"style":351},"public bool IsActive  \n{  \n    get => (bool)GetValue(IsActiveProperty);  \n    set => SetValue(IsActiveProperty, value);  \n}\n",[141,879,880,885,889,894,899],{"__ignoreMap":351},[355,881,882],{"class":357,"line":358},[355,883,884],{},"public bool IsActive  \n",[355,886,887],{"class":357,"line":364},[355,888,504],{},[355,890,891],{"class":357,"line":370},[355,892,893],{},"    get => (bool)GetValue(IsActiveProperty);  \n",[355,895,896],{"class":357,"line":376},[355,897,898],{},"    set => SetValue(IsActiveProperty, value);  \n",[355,900,901],{"class":357,"line":382},[355,902,903],{},"}\n",[15,905,906],{},"这个地方是依赖属性的CLR包装器，GetValue因为返回的是object，我们必须进行强制转换使用bool。SetValue用于写入。",[346,908,910],{"className":460,"code":909,"language":462,"meta":351,"style":351},"public ContentWrapper() {  \n    this.Background = Brushes.Transparent;  \n    var group = new TransformGroup();  \n    group.Children.Add(new ScaleTransform(1, 1));  \n    group.Children.Add(new TranslateTransform(0, 0));  \n    this.RenderTransform = group;  \n    this.RenderTransformOrigin = new Point(0.5, 0.5); \u002F\u002F 从中心缩放  \n}\n",[141,911,912,917,922,927,932,937,942,947],{"__ignoreMap":351},[355,913,914],{"class":357,"line":358},[355,915,916],{},"public ContentWrapper() {  \n",[355,918,919],{"class":357,"line":364},[355,920,921],{},"    this.Background = Brushes.Transparent;  \n",[355,923,924],{"class":357,"line":370},[355,925,926],{},"    var group = new TransformGroup();  \n",[355,928,929],{"class":357,"line":376},[355,930,931],{},"    group.Children.Add(new ScaleTransform(1, 1));  \n",[355,933,934],{"class":357,"line":382},[355,935,936],{},"    group.Children.Add(new TranslateTransform(0, 0));  \n",[355,938,939],{"class":357,"line":388},[355,940,941],{},"    this.RenderTransform = group;  \n",[355,943,944],{"class":357,"line":394},[355,945,946],{},"    this.RenderTransformOrigin = new Point(0.5, 0.5); \u002F\u002F 从中心缩放  \n",[355,948,949],{"class":357,"line":400},[355,950,903],{},[15,952,953,955,956,959,960,963,964,966],{},[141,954,13],{}," 的 ",[141,957,958],{},"Background"," 默认是 ",[141,961,962],{},"null","。在 WPF\u002FAvalonia 中，",[141,965,962],{}," 意味着**“点击穿透”**（Hit Test Invisible）。也就是说，如果你不设置背景，鼠标点在控件空白处时，事件会直接穿透下去，仿佛这个控件不存在。",[15,968,969,970,973],{},"下面则是创建了一个组合动画，我们创建了一个缩放和变换动画，",[19,971,972],{},"初始化值 (1, 1) 和 (0, 0)","：这是“无变化”状态，保证控件刚显示时是正常的 1:1 大小，位置不动。别忘记编写锚点，很多人会忘记，因为锚点的默认值是0,0 不写的话就会向着左上角收缩（如果你就想要这个效果就随意）。",[15,975,976],{},"终于来到了我们的回调函数",[346,978,980],{"className":460,"code":979,"language":462,"meta":351,"style":351},"private static void OnIsActiveChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)  \n{  \n    var control = (ContentWrapper)d;  \n    bool newValue = (bool)e.NewValue;  \n    if (newValue)  \n    {        \n    control.AnimateIn();  \n    }    \n    else  \n    {  \n        control.AnimateOut();  \n    }}\n",[141,981,982,987,991,996,1001,1006,1011,1016,1020,1025,1029,1034],{"__ignoreMap":351},[355,983,984],{"class":357,"line":358},[355,985,986],{},"private static void OnIsActiveChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)  \n",[355,988,989],{"class":357,"line":364},[355,990,504],{},[355,992,993],{"class":357,"line":370},[355,994,995],{},"    var control = (ContentWrapper)d;  \n",[355,997,998],{"class":357,"line":376},[355,999,1000],{},"    bool newValue = (bool)e.NewValue;  \n",[355,1002,1003],{"class":357,"line":382},[355,1004,1005],{},"    if (newValue)  \n",[355,1007,1008],{"class":357,"line":388},[355,1009,1010],{},"    {        \n",[355,1012,1013],{"class":357,"line":394},[355,1014,1015],{},"    control.AnimateIn();  \n",[355,1017,1018],{"class":357,"line":400},[355,1019,544],{},[355,1021,1022],{"class":357,"line":406},[355,1023,1024],{},"    else  \n",[355,1026,1027],{"class":357,"line":412},[355,1028,529],{},[355,1030,1031],{"class":357,"line":418},[355,1032,1033],{},"        control.AnimateOut();  \n",[355,1035,1036],{"class":357,"line":424},[355,1037,1038],{},"    }}\n",[15,1040,1041],{},"它是一个静态的，因为WPF的依赖属性是注册在类层面上，而不是某个具体的对象，内存里只有一份IsActiveProperty的定义，因为函数是静态的，他不知道哪个控件变了，因此WPF会把出事的控件实例通过参数d传递进来。",[15,1043,1044,1045,338],{},"我们通过了强制类型转换拿到了我们想要的control变量，才能使用AnimatIn和Out。参数e是非常有用的，他有两个属性，一个是OldValue一个是NewValuw以及Property（哪个属性变了），一般我们",[19,1046,1047],{},"还会再利用OldValue实现一个防抖检查",[15,1049,1050],{},"在WPF\u002FAvalonia中，面对频繁开关的正确处理不是防抖，是截断，当新的指令来了的时候就会停止手头的动画，马上开始新的目标，你可能马上就理解了，就是使用取消令牌。",[346,1052,1054],{"className":460,"code":1053,"language":462,"meta":351,"style":351},"private CancellationTokenSource _debounceCts;\n\nprivate static void OnIsActiveChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)\n{\n    var control = (ContentWrapper)d;\n    \n    \u002F\u002F 1. 只要有新变化，先取消之前的计划\n    control._debounceCts?.Cancel();\n    control._debounceCts = new CancellationTokenSource();\n    var token = control._debounceCts.Token;\n\n    \u002F\u002F 2. 延迟执行 (比如等 200ms)\n    Task.Delay(200, token).ContinueWith(t => \n    {\n        if (t.IsCanceled) return; \u002F\u002F 如果期间又变了，这次就作废\n\n        \u002F\u002F 3. 只有等了 200ms 还没新变化，才真正执行 UI 操作\n        control.Dispatcher.Invoke(() => \n        {\n            if ((bool)e.NewValue) control.AnimateIn();\n            else control.AnimateOut();\n        });\n    });\n}\n",[141,1055,1056,1061,1067,1072,1077,1082,1086,1091,1096,1101,1106,1110,1115,1120,1125,1130,1134,1139,1144,1149,1154,1159,1164,1169],{"__ignoreMap":351},[355,1057,1058],{"class":357,"line":358},[355,1059,1060],{},"private CancellationTokenSource _debounceCts;\n",[355,1062,1063],{"class":357,"line":364},[355,1064,1066],{"emptyLinePlaceholder":1065},true,"\n",[355,1068,1069],{"class":357,"line":370},[355,1070,1071],{},"private static void OnIsActiveChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)\n",[355,1073,1074],{"class":357,"line":376},[355,1075,1076],{},"{\n",[355,1078,1079],{"class":357,"line":382},[355,1080,1081],{},"    var control = (ContentWrapper)d;\n",[355,1083,1084],{"class":357,"line":388},[355,1085,603],{},[355,1087,1088],{"class":357,"line":394},[355,1089,1090],{},"    \u002F\u002F 1. 只要有新变化，先取消之前的计划\n",[355,1092,1093],{"class":357,"line":400},[355,1094,1095],{},"    control._debounceCts?.Cancel();\n",[355,1097,1098],{"class":357,"line":406},[355,1099,1100],{},"    control._debounceCts = new CancellationTokenSource();\n",[355,1102,1103],{"class":357,"line":412},[355,1104,1105],{},"    var token = control._debounceCts.Token;\n",[355,1107,1108],{"class":357,"line":418},[355,1109,1066],{"emptyLinePlaceholder":1065},[355,1111,1112],{"class":357,"line":424},[355,1113,1114],{},"    \u002F\u002F 2. 延迟执行 (比如等 200ms)\n",[355,1116,1117],{"class":357,"line":430},[355,1118,1119],{},"    Task.Delay(200, token).ContinueWith(t => \n",[355,1121,1122],{"class":357,"line":436},[355,1123,1124],{},"    {\n",[355,1126,1127],{"class":357,"line":442},[355,1128,1129],{},"        if (t.IsCanceled) return; \u002F\u002F 如果期间又变了，这次就作废\n",[355,1131,1132],{"class":357,"line":448},[355,1133,1066],{"emptyLinePlaceholder":1065},[355,1135,1136],{"class":357,"line":547},[355,1137,1138],{},"        \u002F\u002F 3. 只有等了 200ms 还没新变化，才真正执行 UI 操作\n",[355,1140,1141],{"class":357,"line":553},[355,1142,1143],{},"        control.Dispatcher.Invoke(() => \n",[355,1145,1146],{"class":357,"line":558},[355,1147,1148],{},"        {\n",[355,1150,1151],{"class":357,"line":564},[355,1152,1153],{},"            if ((bool)e.NewValue) control.AnimateIn();\n",[355,1155,1156],{"class":357,"line":570},[355,1157,1158],{},"            else control.AnimateOut();\n",[355,1160,1161],{"class":357,"line":576},[355,1162,1163],{},"        });\n",[355,1165,1166],{"class":357,"line":582},[355,1167,1168],{},"    });\n",[355,1170,1171],{"class":357,"line":588},[355,1172,903],{},[1174,1175,1176],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":351,"searchDepth":364,"depth":364,"links":1178},[1179,1180],{"id":12,"depth":370,"text":13},{"id":457,"depth":370,"text":457},"md",{},"\u002Fcsharp\u002Fwpf\u002F继承contentcontrol来管理内容的加载",{"description":351},"csharp\u002FWPF\u002F继承ContentControl来管理内容的加载","ygKp6TR7VdA7n0siN9auT9PwWfmir4pCtRW3vK7QQME",1791042466505]