http://sdasrath.com
Additionally, I am updating links to zip files on my new site. It's a work in progress. Email me if something is not working (sdasrath@outlook.com)
[Veritas Vos Liberabit]
Here is a simple C# snippet for ReSharper (should work on most versions) to simplify the creation of ViewModel properties. It is clear that creating properties in the ViewModel can be a tedious and repetitive process, especially when there are several involved. To create the snippet, you need to add a new Live Template in R#.
In Visual Studio under the ReSharper menu item, select LiveTemplates... and you will see Fig. 1.
Under the User Templates node, select the New Template option from the toolbar and you will be taken to the Template creation page. Here you can enter the shortcut used to toggle the snippet and a description. I used vmp (ViewModel Property) for my shortcut here. Simply copy and paste the code below into the window and I will explain the changes you need to make.
private $TYPE$ _$NAMEFIELD$;
$END$
public $TYPE$ $NAME$
{
get {return _$NAMEFIELD$; }
set
{
if(_$NAMEFIELD$ == value) return;
_$NAMEFIELD$ = value;
OnPropertyChanged("$NAME$");
}
}
The artifacts enclosed between dollar signs ($) can be thought of as variables that you can replace once the snippet has been activated. If we follow the naming convention of labeling fields starting with an underscore and all properties begin with uppcase letter, you will see that if you leave things the way they are as in Fig. 2, you will not get the anticipated result.
This is where the options in the right pane of the Template window comes into play. There are built in macros to help us get the correct set up. We want the $NAME$ to basically be like $_NAMEFIELD$ but without the underscore and the first letter must be upper case. So click the "Choose macro" option next to the NAME identifier in the right pane and from the list, as in Fig. 3, select:
Value of another variable with the first character in upper case
After that, the Template window will look like Fig. 4. Note that we have not yet based the $NAME$ on the $_NAMEFIELD$ variable yet.
Now click the another variable link and you will get a dropdown list to select which variable $NAME$ should use as its basis. This is shown in Fig. 5.
Your snippet is now ready for action!
NOTE: OnPropertyChanged should be replaced by whatever method name you used when you implemented INotifyPropertyChanged. For instance, you may have called yours RaisePropertyChanged instead of OnPropertyChanged, so modify the snippet to best suit your needs.
1 using System.Windows;2 using System.Windows.Controls;3 using DragDropUsingMvvmLight01.Model;45 namespace DragDropUsingMvvmLight016 {7 /// <summary>8 /// Extended class used to change the data template of each ListBoxItem based on some custom requirement.9 /// </summary>10 public class FactionDataTemplateSelector : DataTemplateSelector11 {12 public override DataTemplate SelectTemplate(object item, DependencyObject container)13 {14 var frameworkElement = container as FrameworkElement;1516 if (frameworkElement !=null && item is Contact )17 {18 Contact contact = item as Contact; // Contact is the type hosted in each ListBoxItem1920 if (contact.Crew == Faction.Strawhat)21 return (DataTemplate)frameworkElement.TryFindResource("SourceListBoxItemTemplate");22 return (DataTemplate)frameworkElement.TryFindResource("SourceListBoxDataTemplate02");23 }24 return null;25 }26 }27 }
1 using System.Windows;2 using System.Windows.Controls;3 using DragDropUsingMvvmLight01.Model;45 namespace DragDropUsingMvvmLight016 {7 /// <summary>8 /// Extended class used to change the style of each ListBoxItem based on some custom requirement.9 /// </summary>10 public class ListBoxStyleSelectors : StyleSelector11 {12 public override Style SelectStyle(object item, DependencyObject container)13 {14 FrameworkElement frameworkElement = container as FrameworkElement;1516 if (frameworkElement != null && item is Contact)17 {18 Contact contact = item as Contact; // Contact is the type hosted in each ListBoxItem1920 if (contact.Crew == Faction.Strawhat)21 return (Style)frameworkElement.TryFindResource("SourceListBoxItemStyle1");22 return (Style)frameworkElement.TryFindResource("SourceListBoxItemStyle2");23 }24 return null;25 }26 }27 }
1 using System.Windows;2 using System.Windows.Controls;3 using System.Windows.Documents;4 using System.Windows.Media;56 namespace DragDropUsingMvvmLight017 {8 /// <summary>9 /// An extended adorner class used to attach a visual element to a ListBoxItem as it is being dragged.10 /// </summary>11 public class DraggedAdorner : Adorner12 {13 private readonly ContentPresenter _contentPresenter;14 private readonly ListBoxItem _listBoxItem;15 private Point _updatedMousePosition;1617 public DraggedAdorner(UIElement adornedElement) : base(adornedElement)18 {19 _contentPresenter = new ContentPresenter();2021 _listBoxItem = adornedElement as ListBoxItem;22 if (_listBoxItem != null)23 {24 _contentPresenter.Content = _listBoxItem.Content;25 _contentPresenter.ContentTemplateSelector = _listBoxItem.ContentTemplateSelector;26 }27 _contentPresenter.Opacity = 0.7;28 }2930 protected override Size MeasureOverride(Size constraint)31 {32 _contentPresenter.Measure(constraint);33 return _contentPresenter.DesiredSize;34 }3536 protected override Size ArrangeOverride(Size finalSize)37 {38 _contentPresenter.Arrange(new Rect(finalSize));39 return finalSize;40 }4142 protected override Visual GetVisualChild(int index)43 {44 return _contentPresenter;45 }4647 protected override int VisualChildrenCount48 {49 get { return 1; }50 }5152 public override GeneralTransform GetDesiredTransform(GeneralTransform transform)53 {54 GeneralTransformGroup generalTransformGroup = new GeneralTransformGroup();55 generalTransformGroup.Children.Add(new TranslateTransform(_updatedMousePosition.X, _updatedMousePosition.Y));56 return generalTransformGroup;57 }5859 public void UpdateAdornerPosition(Visual elementToGetAdornerLayerFrom, Point updatedPosition)60 {61 // save the new position of the mouse that is passed in as an arguement as you drag the adorner62 _updatedMousePosition = updatedPosition;63 var adornerLayer = AdornerLayer.GetAdornerLayer(elementToGetAdornerLayerFrom);64 if (adornerLayer != null)65 adornerLayer.Update(AdornedElement);66 }67 }68 }
145 #region Helper Methods146147 /// <summary>148 /// Adds an adorner to an element.149 /// </summary>150 /// <param name="elementToAdorn">Element to add an adorner to.</param>151 /// <param name="elementToGetAdornerLayerFrom">Element to get the AdornerLayer from.</param>152 /// <example>In the case of the ListBox, if you want to adorn each ListBoxItem and the adorner layer of the153 /// containing ListBox is used, then the adorner object gets clipped as it is moved out of the ListBox. In this case,154 /// you need a layer that is higher up the visual tree to allow the adorner to be visible anywhere and not be clipped.155 /// </example>156 public void AddAdorner(UIElement elementToAdorn, Visual elementToGetAdornerLayerFrom)157 {158 // get the adorner layer to attach the adorner to159 var adornerLayer = AdornerLayer.GetAdornerLayer(elementToGetAdornerLayerFrom);160 _draggedAdorner = new DraggedAdorner(elementToAdorn);161 adornerLayer.Add(_draggedAdorner);162 }163164 /// <summary>165 /// Removes an adorner from an element.166 /// </summary>167 /// <param name="adornedElement">The element that has an adorner associated with it.</param>168 /// /// <param name="elementToGetAdornerLayerFrom">Element to get the AdornerLayer from.</param>169 public void RemoveAdorner(UIElement adornedElement, Visual elementToGetAdornerLayerFrom)170 {171 var adornerLayer = AdornerLayer.GetAdornerLayer(elementToGetAdornerLayerFrom);172 var adorners = adornerLayer.GetAdorners(adornedElement);173174 if (adorners == null) return;175176 var dragAdorner = adorners[0] as DraggedAdorner;177 if (dragAdorner != null)178 {179 adornerLayer.Remove(dragAdorner);180 }181 }182 #endregion
36 <ListBox x:Name="dragSource"37 Grid.Row="1"38 MinWidth="100"39 MinHeight="40"40 Margin="0,0,0,0"41 AllowDrop="True"42 Background="AliceBlue"43 ItemContainerStyleSelector="{DynamicResource styleSelector}"44 ItemsPanel="{DynamicResource SourceListBoxItemsPanelTemplate}"45 ItemsSource="{Binding Contacts}"46 ItemTemplateSelector="{DynamicResource dataTemplateSelector}"47 Style="{DynamicResource ListBoxStyle1}">48 <i:Interaction.Triggers>49 <i:EventTrigger EventName="PreviewMouseLeftButtonDown">50 <cmd:EventToCommand Command="{Binding PreviewMouseLeftButtonDownCommand, Mode=OneWay}" PassEventArgsToCommand="True" />51 </i:EventTrigger>52 <i:EventTrigger EventName="DragOver">53 <cmd:EventToCommand Command="{Binding DragOverCommand, Mode=OneWay}" PassEventArgsToCommand="True" />54 </i:EventTrigger>55 <i:EventTrigger EventName="Drop">56 <cmd:EventToCommand Command="{Binding DropSourceCommand, Mode=OneWay}" PassEventArgsToCommand="True" />57 </i:EventTrigger>58 </i:Interaction.Triggers>59 </ListBox>6061 <Border Grid.Row="2" Height="20" />6263 <TextBlock Grid.Row="3"64 Background="White"65 FontSize="18"66 Text="Listbox to drop to" />6768 <ListBox x:Name="dropTarget"69 Grid.Row="4"70 MinWidth="100"71 MinHeight="117"72 Margin="0,0,0,0"73 AllowDrop="True"74 Background="#FFE4F3FD"75 ItemContainerStyleSelector="{DynamicResource styleSelector}"76 ItemsPanel="{DynamicResource SourceListBoxItemsPanelTemplate}"77 ItemsSource="{Binding TargetContacts}"78 ItemTemplateSelector="{DynamicResource dataTemplateSelector}"79 Style="{DynamicResource ListBoxStyle1}">80 <i:Interaction.Triggers>81 <i:EventTrigger EventName="Drop">82 <cmd:EventToCommand Command="{Binding DropTargetCommand, Mode=OneWay}" PassEventArgsToCommand="True" />83 </i:EventTrigger>84 <i:EventTrigger EventName="DragOver">85 <cmd:EventToCommand Command="{Binding DragOverCommand, Mode=OneWay}" PassEventArgsToCommand="True" />86 </i:EventTrigger>87 </i:Interaction.Triggers>88 </ListBox>
72 PreviewMouseLeftButtonDownCommand = new RelayCommand<MouseButtonEventArgs>(73 e =>74 {75 // get dragged listbox76 ListBox listBox = e.Source as ListBox;77 ListBoxItem listBoxItem = VisualHelper.FindAncestor<ListBoxItem>((DependencyObject)e.OriginalSource);7879 // set up shared states80 _listBoxItem = listBoxItem; // adorned element81 _topLevelGrid = GetTopLevelGrid(e); // element to get an adorner layer from higher up the logical tree than the listboxitem8283 // Find the data behind the listBoxItem84 if (listBox == null || listBoxItem == null) return;8586 Contact contact = (Contact)listBox.ItemContainerGenerator.ItemFromContainer(listBoxItem);8788 AddAdorner(listBoxItem, _topLevelGrid);8990 // Initialize the drag & drop operation91 DataObject dragData = new DataObject("myContactData", contact);92 DragDrop.DoDragDrop(listBoxItem, dragData, DragDropEffects.Move);93 }94 );
1 using System.Windows;2 using System.Windows.Media;34 namespace DragDropUsingMvvmLight015 {6 /// <summary>7 /// Walks up the visual tree to find the ancestor of a given type.8 /// </summary>9 internal static class VisualHelper10 {11 /// <summary>12 /// Recursive method to walk up the visual tree to return an ancestor type of the supplied type.13 /// </summary>14 /// <typeparam name="T">Type of ancestor to search for.</typeparam>15 /// <param name="current">Type to start search from.</param>16 /// <returns></returns>17 internal static T FindAncestor<T>(DependencyObject current) where T : DependencyObject18 {19 do20 {21 if (current is T)22 {23 return (T)current;24 }25 current = VisualTreeHelper.GetParent(current);26 } while (current != null);27 return null;28 }29 }30 }
96 DragOverCommand = new RelayCommand<DragEventArgs>(97 e =>98 {99 if (!e.Data.GetDataPresent("contact"))100 {101 e.Effects = DragDropEffects.None;102 }103104 var currentMousePosition = e.GetPosition(_topLevelGrid);105106 if (_topLevelGrid != null && _draggedAdorner != null)107 _draggedAdorner.UpdateAdornerPosition(_topLevelGrid, currentMousePosition);108 }109 );
111 DropTargetCommand = new RelayCommand<DragEventArgs>(112 e =>113 {114 if(!e.Data.GetDataPresent("myContactData")) return;115 Contact contact = e.Data.GetData("myContactData") as Contact;116117 _targetContacts.Add(contact); // add to new collection118 _contacts.Remove(contact); // remove from source collection119120 // pass in the root grid since its adorner layer was used to add ListBoxItems adorners to121 RemoveAdorner(_listBoxItem, _topLevelGrid);122 });123124 // if dropping on the source list, remove the adorner125 DropSourceCommand = new RelayCommand<DragEventArgs>(e => RemoveAdorner(_listBoxItem, _topLevelGrid));