public override bool ApplyTemplate() { if (this.IsInitialized && this.visualChild == null) { Visual visual = this.Content as Visual; if (visual == null && this.Content != null) { DataTemplate template = this.ContentTemplate; if (template == null) { DataTemplateKey key = new DataTemplateKey(this.Content.GetType()); template = this.TryFindResource(key) as DataTemplate; } if (template != null) { visual = template.CreateVisualTree(this); FrameworkElement fe = visual as FrameworkElement; if (fe != null) { fe.DataContext = this.Content; } } else { visual = new TextBlock { Text = this.Content.ToString(), }; } } if (visual != null) { this.visualChild = visual; this.AddVisualChild(this.visualChild); this.OnApplyTemplate(); return true; } } return false; }
public override DataTemplate SelectTemplate(object item, DependencyObject container) { if (item == null) { return(null); } var frameworkElement = container as FrameworkElement; if (frameworkElement == null) { return(null); } var type = item.GetType(); if (type == typeof(JProperty)) { var jProperty = item as JProperty; switch (jProperty.Value.Type) { case JTokenType.Object: return(frameworkElement.FindResource("ObjectPropertyTemplate") as DataTemplate); case JTokenType.Array: return(frameworkElement.FindResource("ArrayPropertyTemplate") as DataTemplate); default: return(frameworkElement.FindResource("PrimitivePropertyTemplate") as DataTemplate); } } var key = new DataTemplateKey(type); return(frameworkElement.FindResource(key) as DataTemplate); }
IEnumerable <string> GetDataTemplateStrings(FrameworkElement fwElem) { var obj = Page.GetStringsObject(); if (obj == null) { return(Array.Empty <string>()); } if (obj is UIElement uiElem) { return(GetStrings(uiElem)); } var key = new DataTemplateKey(obj as Type ?? obj.GetType()); var dt = fwElem.TryFindResource(key) as DataTemplate; if (dt == null) { return(Array.Empty <string>()); } return(GetStrings(dt.LoadContent())); }
/// <summary> /// If the Template represented by a group of baml records is stored in a dictionary, this /// method will extract the key used for this dictionary from the passed /// collection of baml records. For ControlTemplate, this is the styleTargetType. /// For DataTemplate, this is the DataTemplateKey containing the DataType. /// </summary> //CASRemoval:[StrongNameIdentityPermission(SecurityAction.InheritanceDemand, PublicKey = Microsoft.Internal.BuildInfo.WCP_PUBLIC_KEY_STRING)] internal override object GetDictionaryKey(BamlRecord startRecord, ParserContext parserContext) { object key = null; int numberOfElements = 0; BamlRecord record = startRecord; short ownerTypeId = 0; while (record != null) { if (record.RecordType == BamlRecordType.ElementStart) { BamlElementStartRecord elementStart = record as BamlElementStartRecord; if (++numberOfElements == 1) { // save the type ID of the first element (i.e. <ControlTemplate>) ownerTypeId = elementStart.TypeId; } else { // We didn't find the key before a reading the // VisualTree nodes of the template break; } } else if (record.RecordType == BamlRecordType.Property && numberOfElements == 1) { // look for the TargetType property on the <ControlTemplate> element // or the DataType property on the <DataTemplate> element BamlPropertyRecord propertyRecord = record as BamlPropertyRecord; short attributeOwnerTypeId; string attributeName; BamlAttributeUsage attributeUsage; parserContext.MapTable.GetAttributeInfoFromId(propertyRecord.AttributeId, out attributeOwnerTypeId, out attributeName, out attributeUsage); if (attributeOwnerTypeId == ownerTypeId) { if (attributeName == TargetTypePropertyName) { key = parserContext.XamlTypeMapper.GetDictionaryKey(propertyRecord.Value, parserContext); } else if (attributeName == DataTypePropertyName) { object dataType = parserContext.XamlTypeMapper.GetDictionaryKey(propertyRecord.Value, parserContext); Exception ex = TemplateKey.ValidateDataType(dataType, null); if (ex != null) { ThrowException(SRID.TemplateBadDictionaryKey, parserContext.LineNumber, parserContext.LinePosition, ex); } // key = new DataTemplateKey(dataType); } } } else if (record.RecordType == BamlRecordType.PropertyComplexStart || record.RecordType == BamlRecordType.PropertyIListStart || record.RecordType == BamlRecordType.ElementEnd) { // We didn't find the targetType before a complex property like // FrameworkTemplate.VisualTree or the </ControlTemplate> tag or // TableTemplate.Tree or the </TableTemplate> tag break; } record = record.Next; } if (key == null) { ThrowException(SRID.StyleNoDictionaryKey, parserContext.LineNumber, parserContext.LinePosition, null); } return key; }
public override DataTemplate SelectTemplate(object item, ItemsControl parentItemsControl) { var key = new DataTemplateKey(item.GetType()); return((DataTemplate)parentItemsControl.FindResource(key)); }
/// <summary> /// Appies the binding to the breadcrumb item. /// </summary> public void ApplyBinding() { object item = DataContext; if (item == null) { return; } BreadcrumbItem root = this; DataTemplate template = HeaderTemplate; DataTemplateSelector templateSelector = HeaderTemplateSelector; if (templateSelector != null) { template = templateSelector.SelectTemplate(item, root); } if (template == null) { DataTemplateKey key = GetResourceKey(item); if (key != null) { template = TryFindResource(key) as DataTemplate; } } root.SelectedItem = null; HierarchicalDataTemplate hdt = template as HierarchicalDataTemplate; if (template != null) { root.Header = template.LoadContent(); } else { root.Header = item; } root.DataContext = item; if (hdt != null) { // bind the Items to the hierarchical data template: root.SetBinding(BreadcrumbItem.ItemsSourceProperty, hdt.ItemsSource); } BreadcrumbBar bar = BreadcrumbBar; if (bar != null) { if (TraceBinding == null) { TraceBinding = bar.TraceBinding; } if (ImageBinding == null) { ImageBinding = bar.ImageBinding; } } if (TraceBinding != null) { root.SetBinding(BreadcrumbItem.TraceProperty, TraceBinding); } if (ImageBinding != null) { root.SetBinding(BreadcrumbItem.ImageProperty, ImageBinding); } ApplyProperties(item); }
/// <summary> /// If the Template represented by a group of baml records is stored in a dictionary, this /// method will extract the key used for this dictionary from the passed /// collection of baml records. For ControlTemplate, this is the styleTargetType. /// For DataTemplate, this is the DataTemplateKey containing the DataType. /// </summary> //CASRemoval:[StrongNameIdentityPermission(SecurityAction.InheritanceDemand, PublicKey = Microsoft.Internal.BuildInfo.WCP_PUBLIC_KEY_STRING)] internal override object GetDictionaryKey(BamlRecord startRecord, ParserContext parserContext) { object key = null; int numberOfElements = 0; BamlRecord record = startRecord; short ownerTypeId = 0; while (record != null) { if (record.RecordType == BamlRecordType.ElementStart) { BamlElementStartRecord elementStart = record as BamlElementStartRecord; if (++numberOfElements == 1) { // save the type ID of the first element (i.e. <ControlTemplate>) ownerTypeId = elementStart.TypeId; } else { // We didn't find the key before a reading the // VisualTree nodes of the template break; } } else if (record.RecordType == BamlRecordType.Property && numberOfElements == 1) { // look for the TargetType property on the <ControlTemplate> element // or the DataType property on the <DataTemplate> element BamlPropertyRecord propertyRecord = record as BamlPropertyRecord; short attributeOwnerTypeId; string attributeName; BamlAttributeUsage attributeUsage; parserContext.MapTable.GetAttributeInfoFromId(propertyRecord.AttributeId, out attributeOwnerTypeId, out attributeName, out attributeUsage); if (attributeOwnerTypeId == ownerTypeId) { if (attributeName == TargetTypePropertyName) { key = parserContext.XamlTypeMapper.GetDictionaryKey(propertyRecord.Value, parserContext); } else if (attributeName == DataTypePropertyName) { object dataType = parserContext.XamlTypeMapper.GetDictionaryKey(propertyRecord.Value, parserContext); Exception ex = TemplateKey.ValidateDataType(dataType, null); if (ex != null) { ThrowException(SRID.TemplateBadDictionaryKey, parserContext.LineNumber, parserContext.LinePosition, ex); } // key = new DataTemplateKey(dataType); } } } else if (record.RecordType == BamlRecordType.PropertyComplexStart || record.RecordType == BamlRecordType.PropertyIListStart || record.RecordType == BamlRecordType.ElementEnd) { // We didn't find the targetType before a complex property like // FrameworkTemplate.VisualTree or the </ControlTemplate> tag or // TableTemplate.Tree or the </TableTemplate> tag break; } record = record.Next; } if (key == null) { ThrowException(SRID.StyleNoDictionaryKey, parserContext.LineNumber, parserContext.LinePosition, null); } return(key); }
private object TryFindResource(Type associatedType, IApplicationRuntime application) { var key = new DataTemplateKey(associatedType); return(application.TryFindResource(key)); }
/// <summary> /// Overrides the default arrangement of a Canvas. /// </summary> /// <param name="arrangeSize">The largest possible size for the canvas.</param> /// <returns>The actual size used by this canvas.</returns> protected override Size MeasureOverride(Size constraint) { // This calculates the visible area of the virtual canvas. Note that the 'MeasureOverride' is called before the // 'OnRenderSizeChanged' so the rectangle used for clipping can't be used here because it hasn't been calclated // properly yet. Rect viewport = new Rect(this.rectangleGeometry.Rect.Location, constraint); // IMPORTANT CONCEPT: The FrameworkElements are recycled for performance. Creating the user interface elements and // adding and removing them from the canvas are very time consuming tasks. The XAML for the reports contains templates // used to create FrameworkElements for a given CLR type. It turns out that any CLR object of a given type can use any // FrameworkElement created for that given type. So a factory of sorts is created for building and reusing the // framework elements based on a CLR type. A screen is drawn by first reclaiming all the elements that are no longer // visible. These elements are not removed from the screen in the first pass. The secod pass draws the visible area // of the report using reclaimed elements when it can, creating new FrameworkElements when it can't. The important // performance kick here is that the elements are not actually removed from the screen during the reclaimation pass and // the drawing pass. All elements are put into this list when during the reclaimation cycle. If they are still in // this list after the drawing pass, then they are not visible and can be removed from the canvas. This is the // reclamation cycle. All the user interface elements that have become invisible are pushed back into the element // cache where they can be used again when the viewport is updated. foreach (UIElement uiElement in this.Children) { if (uiElement is FrameworkElement) { // This element will be examined to see if it needs to be recycled. FrameworkElement frameworkElement = uiElement as FrameworkElement; // The 'ReportCell' is the virtual information behind the user interface element and is attached to all the // visual elements in the canvas. It is used here to indicate whether the associated FrameworkElement is // invisible. ReportCell reportCell = DynamicReport.GetCell(frameworkElement); try { if (reportCell != null) { // This will test the virtual cell to see if it is invisible. Note that any cell that touches the right or // bottom edge of the viewport is considered to be invisible. There is no part of these cells that can // actually be seen, whereas the left and top edges are visible. Rect rect = reportCell.ActualRect; if (((viewport.Top > rect.Top || rect.Top >= viewport.Bottom) && (viewport.Top >= rect.Bottom || rect.Bottom > viewport.Bottom)) || ((viewport.Left > rect.Left || rect.Left >= viewport.Right) && (viewport.Left >= rect.Right || rect.Right > viewport.Right))) { // When the framework element has become invisible, it is placed back in the cache based on the CLR // type of the object it can display. It can be recycled for use with similar types when the new // viewport is constructed in the second pass. Type contentType = reportCell.Content.GetType(); Stack <FrameworkElement> elementStack; if (!this.elementCache.TryGetValue(contentType, out elementStack)) { elementStack = new Stack <FrameworkElement>(); this.elementCache.Add(contentType, elementStack); } elementStack.Push(frameworkElement); // This disconnects the visual element from the virtual ReportCell and the virtual ReportCell from the // visual element. DynamicReport.SetCell(frameworkElement, ReportCell.Empty); this.elementTable.Remove(reportCell); // The focus scope for this canvas must be cleared when the element that had the focus is recycled. // This method 'virtualizes' the handling of the focus. The virtual focus is saved in the 'IsFocused' // property of the ReportCell while the cell is invisible. When this virtual cell becomes visible // again, the keyboard focus will be given back to to user interface element used to instantiate the // virtual cell. if (reportCell.IsFocused) { FocusManager.SetFocusedElement(this.ReportGrid, null); if (frameworkElement.IsKeyboardFocusWithin) { Keyboard.Focus(this.ReportGrid); } } // All these bindings need to be released when a cell is no longer visible. There seems to be a very // practical limitation to how many binding updates can be done by the operating system. Failure to // release a binding when a user element is no longer visible will quickly result all the resources // being used. BindingOperations.ClearBinding(frameworkElement, Canvas.LeftProperty); BindingOperations.ClearBinding(frameworkElement, Canvas.TopProperty); BindingOperations.ClearBinding(frameworkElement, FrameworkElement.WidthProperty); BindingOperations.ClearBinding(frameworkElement, FrameworkElement.HeightProperty); BindingOperations.ClearBinding(frameworkElement, DynamicReport.IsEvenProperty); BindingOperations.ClearBinding(frameworkElement, DynamicReport.IsSelectedProperty); } } } catch (Exception exception) { String message = reportCell.ReportColumn == null ? "ReportColumn is null" : reportCell.ReportRow == null ? "ReportRow is null" : "not sure why"; Log.Error("{0}: {1} ({2})\n{3}", exception.GetType(), exception.Message, message, exception.StackTrace); } } } // This pass will construct the visible part of the canvas. The main idea is to find the virtual cells that appear in // the viewport and associate the cell with a visual element. If a visual element can be found in the cache, it is // used, otherwise one is created from a template. foreach (ReportRow reportRow in this.ReportGrid.Rows) { if (reportRow.IsEmpty) { continue; } // Only rows that appear in the visible part of the canvas are considered. Evaluating the rows this way quickly // removes the number of cells that need to be checked. if (((viewport.Top <= reportRow.Top && reportRow.Top < viewport.Bottom) || (viewport.Top < reportRow.Bottom && reportRow.Bottom <= viewport.Bottom))) { // At this point we have a row that is part of the visible canvas. This will see which of the columns are // visible. foreach (ReportColumn reportColumn in this.ReportGrid.Columns) { // Note that columns that fall on the right edge are excluded. Even though they appear to intersect with // the viewport, there is no part of these columns that's actally visible. if ((viewport.Left <= reportColumn.Left && reportColumn.Left < viewport.Right) || (viewport.Left < reportColumn.Right && reportColumn.Right <= viewport.Right)) { // The cell exists at a virtual location in the document coordinate system. They are instantiated and // added to the canvas when the become visible and are remove from the canvas when not visible. This // is how a very large document can be viewed with a relatively small number of visual elements and // bindings. ReportCell reportCell = reportRow[reportColumn]; // If this cell doesn't have a framework element associated with it, then one is either recycled // from the cache or created from a template. FrameworkElement frameworkElement; if (!this.elementTable.TryGetValue(reportCell, out frameworkElement)) { // Each Framework element will work with one and only one CLR type. The content of the // ReportCell determines what kind of FrameworkElement instance is used to display the data in // that cell. Type contentType = reportCell.Content.GetType(); // The CLR type of the content is used to find a stack of FrameworkElements that can be used to // display that content. Stack <FrameworkElement> elementStack; if (!this.elementCache.TryGetValue(contentType, out elementStack)) { elementStack = new Stack <FrameworkElement>(); this.elementCache.Add(contentType, elementStack); } // If there are no instances of a visual element that can be used to display the content of // this ReportCell, then one is generated from the template. Otherwise, a recycled element is // used. Note that all default focus styles are removed from visual elements on the canvas as // there these elements have a custom style applied which functions like the Microsoft Excel // focus and selection. if (elementStack.Count == 0) { DataTemplateKey dataTemplateKey = new DataTemplateKey(reportCell.Content.GetType()); DataTemplate dataTemplate = this.ReportGrid.Resources[dataTemplateKey] as DataTemplate; if (dataTemplate != null) { frameworkElement = dataTemplate.LoadContent() as FrameworkElement; frameworkElement.FocusVisualStyle = null; } } else { frameworkElement = elementStack.Pop(); } // This associates the visual element with the ReportCell that contains the information about // the location of that element in the virtual document coordinate space. The 'elementTable' // contains the reciprocal relation. DynamicReport.SetCell(frameworkElement, reportCell); this.elementTable.Add(reportCell, frameworkElement); // The data context for the XAML elements is the content of the cell, not the ReportCell. // This is done intensionally to hide the implementation details of how elements are positioned // on the screen. It is also done to simplify the programming model for the XAML code. frameworkElement.DataContext = reportCell.Content; // Bind the element's 'Left' property of the element to the column's position. Binding leftBinding = new Binding("ActualLeft"); leftBinding.Source = reportCell.ReportColumn; BindingOperations.SetBinding(frameworkElement, Canvas.LeftProperty, leftBinding); // Bind the element's 'Top' property of the element to the row's position. Binding topBinding = new Binding("ActualTop"); topBinding.Source = reportCell.ReportRow; BindingOperations.SetBinding(frameworkElement, Canvas.TopProperty, topBinding); // Bind the element's 'Width' property of the element to the column's width. Binding widthBinding = new Binding("ActualWidth"); widthBinding.Source = reportCell.ReportColumn; BindingOperations.SetBinding(frameworkElement, FrameworkElement.WidthProperty, widthBinding); // Bind the element's 'Height' property of the element to the row's height. Binding heightBinding = new Binding("ActualHeight"); heightBinding.Source = reportCell.ReportRow; BindingOperations.SetBinding(frameworkElement, FrameworkElement.HeightProperty, heightBinding); // Bind the element's 'IsSelected' property to the cell's property. This property is used to // highlight the selected cells. Binding isSelectedBinding = new Binding("IsSelected"); isSelectedBinding.Source = reportCell; BindingOperations.SetBinding(frameworkElement, DynamicReport.IsSelectedProperty, isSelectedBinding); // Bind the 'Height' property of the element to the row's 'IsEven' property. This property is // generally used to shade every other line to make it easier to follow the information on a // row. Binding evenBinding = new Binding("IsEven"); evenBinding.Source = reportCell.ReportRow; BindingOperations.SetBinding(frameworkElement, DynamicReport.IsEvenProperty, evenBinding); } // New and recycled elements need to be added to the canvas to become part of the visible report. if (frameworkElement.Parent == null) { this.Children.Add(frameworkElement); } // The logical (and keyboard) focus is restored to the element that has the virtual focus when the // virtual cell is made visible again. Note that the logical focus is only moved when the canvas // has the keyboard focus. This prevents a scenario where the canvas grabs the input focus away // from another window when the input focus is made visible again. if (reportCell.IsFocused) { if (this.IsKeyboardFocusWithin) { if (FocusManager.GetFocusedElement(this.ReportGrid) != frameworkElement) { FocusManager.SetFocusedElement(this.ReportGrid, frameworkElement); } } } } } } } // At this point, all the elements that can be recycled have been recycled. The remaining elements on the canvas that // are not associated with a virtual report element need to be removed. for (int index = 0; index < this.Children.Count;) { UIElement uiElement = this.Children[index]; if (DynamicReport.GetCell(uiElement) == ReportCell.Empty) { this.Children.RemoveAt(index); } else { index++; } } // The base class takes care of the hard work of measuring the visible user interface elements on the canvas. return(base.MeasureOverride(constraint)); }
public object TryFindResource(DataTemplateKey key) { return(this._wpfApplication.TryFindResource(key)); }
private void ItemsSource_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { // なんか怖いので全部UIスレッドにディスパッチする Application.Current.Dispatcher.Invoke(() => { switch (e.Action) { case NotifyCollectionChangedAction.Add: foreach (var item in e.NewItems) { // VMの型からDataTemplateを探し、対応するViewを生成する var key = new DataTemplateKey(item.GetType()); var template = TryFindResource(key) as DataTemplate; if (template != null) { var content = template.LoadContent(); if (content is FrameworkElement) { var fe = content as FrameworkElement; fe.DataContext = item; } if (content is Window) { var win = content as Window; AddWindow(win); } else if (content is IVolatileWindowHandler) { var vol = content as IVolatileWindowHandler; ShowAndDeleteVolatileWindow(vol); } else { // 自動でラップすることもできるが、バグの温床になりそうなので例外 throw new InvalidCastException("Content of DataTemplate must be Window"); } } else { // テンプレートがない場合エラーにしてもいいが、単にウィンドウを表示する var win = new Window { Content = item, }; AddWindow(win); } } break; case NotifyCollectionChangedAction.Remove: foreach (var item in e.OldItems) { var win = Items.Where(w => w.DataContext == item).FirstOrDefault(); if (win != null) { win.Close(); if (win.IsLoaded) { // IsLoadedでCloseがキャンセルされたかどうかわかるからエラーにする...と思ったけど、 // 非同期になっていてうまく判断できなかった //throw new InvalidOperationException("Dont cancel Closing while removing ViewModel from ItemsSource"); } Items.Remove(win); } } break; case NotifyCollectionChangedAction.Move: var fromIndex = e.OldStartingIndex; var toIndex = e.NewStartingIndex; if (fromIndex < 0 || fromIndex >= Items.Count || toIndex < 0 || toIndex >= Items.Count) { throw new IndexOutOfRangeException("index in CollectionChanged parameter from ItemsSource seems to be wrong"); } var movingItem = Items.Where(w => w.DataContext == e.NewItems[0]).First(); if (toIndex == Items.Count - 1) { // 末尾への移動だった場合、Activateする なんか無理矢理すぎないか movingItem.Activate(); } break; case NotifyCollectionChangedAction.Reset: // 全削除 for (int i = Items.Count - 1; i >= 0; --i) { var win = Items[i]; win.Close(); Items.RemoveAt(i); } break; default: break; } }); }
private DataTemplate GetModelDataTemplate(Type modelType) { var key = new DataTemplateKey(modelType); return(_paginatorSource.TryFindResource(key) as DataTemplate); }
/// <summary> /// Выполнить поиск шаблона данных по визуальному дереву xaml /// </summary> /// <param name="instance">Объект относительно которого выполняется поиск</param> /// <param name="dataType">Тип для которого осуществляется поиск ресурсов</param> /// <returns>Шаблон данных</returns> public static DataTemplate FindDataTemplate(FrameworkElement instance, Type dataType) { var key = new DataTemplateKey(dataType); return(instance.TryFindResource(key) as DataTemplate); }
public object TryFindResource(DataTemplateKey key) { return(null); }