2017-08-18 5 views
4

Ich arbeite mit der WPF-Strukturlistenansicht von DevExpress und stieß auf ein allgemeineres Problem beim Umbenennen von Eigenschaften der Objekte, die als Elementquelle verwendet werden. In der Baumlistenansicht ist es erforderlich, den ParentFieldName und den KeyFieldName anzugeben (mit denen die Struktur der Struktur bestimmt wird). Diese Felder sind Strings.Gibt es ein XAML-Äquivalent zu nameof?

Dies hat zu Problemen beim Refactoring des Codes geführt. Wenn Sie beispielsweise eine Eigenschaft der Objekte, die ich als ItemSource verwende, umbenennen, wird die Baumansicht unterbrochen, da ParentFieldName und KeyFieldName nicht mehr mit den Eigenschaftsnamen synchronisiert sind. Ich habe dieses Problem durch Erstellen von Eigenschaften in meinem Ansichtsmodell "ParentFieldName" und "KeyFieldName" behoben, die nameof verwenden, um der Ansicht den Eigenschaftsnamen zu präsentieren.

Hier ist eine abgespeckte Version der Steuerung:

<UserControl 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid"    
      d:DesignHeight="300" d:DesignWidth="300"> 
     <UserControl.DataContext> 
      <ViewModel /> 
     </UserControl.DataContext> 
     <dxg:TreeListControl AutoGenerateColumns="AddNew" 
         EnableSmartColumnsGeneration="True" ItemsSource="{Binding Results}"       
         SelectionMode="Row"> 
      <dxg:TreeListControl.View> 
       <dxg:TreeListView         
           ParentFieldName="{Binding ParentIdFieldName}" KeyFieldName="{Binding NodeIdFieldName}" 
           ShowHorizontalLines="False" ShowVerticalLines="False" 
           ShowNodeImages="True"/> 
      </dxg:TreeListControl.View> 
     </dxg:TreeListControl> 
    </UserControl> 

Und das Viewmodel:

using DevExpress.Mvvm;  

public sealed class ViewModel : ViewModelBase 
{ 
    public string ParentIdFieldName => nameof(TreeNode.ParentId); 

    public string NodeIdFieldName => nameof(TreeNode.NodeId); 

    public ObservableCollection<TreeNode> Results 
    { 
     get => GetProperty(() => Results); 
     set => SetProperty(() => Results, value); 
    } 
} 

Und der Baumknoten:

public sealed class TreeNode 
{ 
    public int ParentId {get; set;} 
    public int NodeId {get; set;} 
} 

Meine Lösung gut funktioniert, aber ich fragte sich, ob es einen besseren Weg dafür gab. Kann ich beispielsweise in XAML etwas tun, das dem Namen des Aufrufs entspricht und nicht an diesen ParentIdFieldName und NodeIdFieldName im Ansichtsmodell bindet?

Ich weiß, dies könnte als ein Problem mit DevExpress Kontrolle beschrieben werden. Ich bin jedoch daran interessiert, ob der Ansatz, mit dem ich das umgehen konnte, verbessert werden kann. Gibt es eine Möglichkeit, dies einfacher direkt im XAML zu machen?

Ich entschuldige mich im Voraus, wenn der Code, den ich zur Verfügung gestellt habe, nicht kompiliert. Ich habe das, woran ich arbeite, deutlich reduziert, um ein Beispiel zu geben.

Antwort

8

Sie können eine benutzerdefinierte Markuperweiterung erstellen.

Zum Beispiel:

[ContentProperty(nameof(Member))] 
public class NameOfExtension : MarkupExtension 
{ 
    public Type Type { get; set; } 
    public string Member { get; set; } 

    public override object ProvideValue(IServiceProvider serviceProvider) 
    { 
     if (serviceProvider == null) 
      throw new ArgumentNullException(nameof(serviceProvider)); 

     if (Type == null || string.IsNullOrEmpty(Member) || Member.Contains(".")) 
      throw new ArgumentException("Syntax for x:NameOf is Type={x:Type [className]} Member=[propertyName]"); 

     var pinfo = Type.GetRuntimeProperties().FirstOrDefault(pi => pi.Name == Member); 
     var finfo = Type.GetRuntimeFields().FirstOrDefault(fi => fi.Name == Member); 
     if (pinfo == null && finfo == null) 
      throw new ArgumentException($"No property or field found for {Member} in {Type}"); 

     return Member; 
    } 
} 

Verwendungsbeispiel:

enter image description here

Verwandte Themen