- ResourceDictionaryã®ã¡ã¢ãªè©°ãŸãã€ã³ã¹ã¿ã³ã¹
- ã¡ã¢ãªãªãŒã¯
- èŠèŠçãªã³ã³ããŒãã³ããšã¹ã¿ã€ã«ã®ç¶æ¿
- ãã€ã³ããšã©ãŒ
- æšæºæ€èšŒããŒã«
- PropertyChangedã€ãã³ãã®èª€çš
- Dispatcherã®éå°äœ¿çš
- ã¢ãŒãã«ãã€ã¢ãã°
- ãã£ã¹ãã¬ã€ããã©ãŒãã³ã¹åæ
- ãããŠãINotifyPropertyChangedã«ã€ããŠããå°ã
- ããšããã®ä»£ããã«
ResourceDictionaryã®ã¡ã¢ãªè©°ãŸãã€ã³ã¹ã¿ã³ã¹
å€ãã®å Žåãéçºè ã¯ã次ã®ãããªãŠãŒã¶ãŒã³ã³ãããŒã«ã®XAMLããŒã¯ã¢ããã«å¿ èŠãªãªãœãŒã¹ãã£ã¯ã·ã§ããªãçŽæ¥æ瀺çã«å«ããŸãã
<UserControl x:Class="SomeProject.SomeControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" <UserControl.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="/Styles/General.xaml" /> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </UserControl.Resources>
äžèŠãããšããããã®ã¢ãããŒãã«ã¯åé¡ã¯ãããŸãã-å¶åŸ¡èŠçŽ ã«å¯ŸããŠæå°éå¿ èŠãªã¹ã¿ã€ã«ã®ã»ãããæå®ããã ãã§ãã ã¢ããªã±ãŒã·ã§ã³ã§ãSomeControlãããããã®ãŠã£ã³ããŠã®10åã®ã€ã³ã¹ã¿ã³ã¹ã«ååšãããšããŸãã åé¡ã¯ããããã®åã€ã³ã¹ã¿ã³ã¹ãäœæãããšãã«ãæå®ããããã£ã¯ã·ã§ããªãåèªã¿åããããåŠçãããã¡ã¢ãªå ã®åå¥ã®ã³ããŒãšããŠä¿åãããããšã§ãã ãã©ã°ã€ã³èŸæžãå€ãã»ã©ãã€ã³ã¹ã¿ã³ã¹ãå€ããªããŸã-ããããå«ããã¥ãŒãåæåããã®ã«ããå€ãã®æéãããããããå€ãã®ã¡ã¢ãªãç¡é§ã«ãªããŸãã å®éã«ã¯ãäžèŠãªResourceDictionaryã«ããã¡ã¢ãªãªãŒããŒã©ã³ãçŽ200ã¡ã¬ãã€ãã§ããã¢ããªã±ãŒã·ã§ã³ãåŠçããå¿ èŠããããŸããã
ãã®åé¡ã解決ããããã®2ã€ã®ãªãã·ã§ã³ãç¥ã£ãŠããŸãã 1ã€ç®ã¯ãApp.xamlã§ã®ã¿å¿ èŠãªãã¹ãŠã®ã¹ã¿ã€ã«èŸæžãæ¥ç¶ããä»ã®å Žæã«ã¯æ¥ç¶ããªãããšã§ãã å°ããªã¢ããªã±ãŒã·ã§ã³ã«ã¯é©ããŠãããããããŸããããè€éãªãããžã§ã¯ãã§ã¯åãå ¥ããããªããããããŸããã 2çªç®ã®æ¹æ³ã¯ãæšæºã®ResourceDictionaryã®ä»£ããã«åŸç¶ã®ãã®ã䜿çšããããšã§ããããã«ãããåã€ã³ã¹ã¿ã³ã¹ã1ã€ã®ã€ã³ã¹ã¿ã³ã¹ã®ã¿ã®ã¡ã¢ãªã«æ ŒçŽãããããã«èŸæžããã£ãã·ã¥ãããŸãã æ®å¿µãªãããWPFã¯äœããã®çç±ã§ãã®ãããªæ©äŒãæäŸããŠããŸããããèªåã§ç°¡åã«å®è£ ã§ããŸãã æãå®å šãªãœãªã¥ãŒã·ã§ã³ã®1ã€ã¯ãæåŸã®åçïŒ http://stackoverflow.com/questions/6857355/memory-leak-when-using-sharedresourcedictionaryïŒã«ãããŸãã
ã¡ã¢ãªãªãŒã¯
ã€ãã³ããªãŒã¯
èªåã¬ããŒãžã³ã¬ã¯ã·ã§ã³ç°å¢ã§ããã¡ã¢ãªãªãŒã¯ã¯ç°¡åã«ååŸã§ããŸãã ãªãŒã¯ã®æãäžè¬çãªåå ã¯ãWPFãããžã§ã¯ãã ãã§ãªãããã®åŸãã³ãã©ãåé€ããªãã€ãã³ããµãã¹ã¯ãªãã·ã§ã³ã§ãã ããã¯ãã¯ãããžãŒèªäœã®åé¡ã§ã¯ãããŸããããã€ãã³ãã¯å€ãã®å ŽåWPFãããžã§ã¯ãã§äœ¿çšããããšã©ãŒã®å¯èœæ§ãé«ããããããã«è©³ãã説æãã䟡å€ããããŸãã
ããšãã°ãã¢ããªã±ãŒã·ã§ã³ã«ã¯ãç·šéãŠã£ã³ããŠã§ããããã£ãå€æŽã§ãããªããžã§ã¯ãã®ãªã¹ãããããŸãã ãã®ãŠã£ã³ããŠãå®è£ ããã«ã¯ãç·šéããããªããžã§ã¯ãã®ããããã£ãå€æŽãããšãã«ããã¥ãŒã¢ãã«å ã§IsModifiedãtrueã«èšå®ããå¿ èŠããããŸããã
ç·šéçšã®ãã¥ãŒã¢ãã«ã次ã®ããã«å®è£ ãããŠãããšããŸãã
public class EntityEditorViewModel { //... public EntityEditorViewModel(EntityViewModel entity) { Entity = entity; Entity.PropertyChanged += (s, e) => IsModified = true; } }
ããã§ãã³ã³ã¹ãã©ã¯ã¿ãŒã¯ããžãã¹ãšã³ãã£ãã£ãšãšãã£ã¿ãŒã®ãã¬ãŒã³ããŒã·ã§ã³ã¢ãã«ã®éã«ã匷åãªããªã³ã¯ã確ç«ããŸãã ãŠã£ã³ããŠã衚瀺ããããã³ã«EntityEditorViewModelã®ã€ã³ã¹ã¿ã³ã¹ãäœæãããšããã®ãããªãªããžã§ã¯ãã¯ã¡ã¢ãªã«èç©ãããããããåç §ããããžãã¹ãšã³ãã£ãã£ããŽãã«ãªã£ãå Žåã«ã®ã¿åé€ãããŸãã
ãã®åé¡ã®1ã€ã®è§£æ±ºçã¯ããã³ãã©ãŒãåé€ããããšã§ãã ããšãã°ãIDisposableãå®è£ ããDisposeïŒïŒã¡ãœããã§ã€ãã³ãããããµãã¹ã¯ã©ã€ã解é€ãããŸãã ããããããã§ãäŸã®ããã«ã©ã ãåŒã§æå®ããããã³ãã©ãŒãç°¡åãªæ¹æ³ã§åé€ããããšã¯ã§ããŸãããã€ãŸãã ããã¯æ©èœããŸããïŒ
// ! entity.PropertyChanged -= (s, e) => IsModified = true;
åé¡ã®æ£ãã解決çãšããŠãCïŒã§ã©ã ãåŒãçŸããåã«åžžã«è¡ãããŠããããã«ãå¥ã®ã¡ãœããã宣èšããIsModifiedã€ã³ã¹ããŒã«ããã®äžã«é 眮ããŠãã³ãã©ãŒãšããŠäœ¿çšããå¿ èŠããããŸãã
ãã ããæ瀺çãªåé€ã䜿çšããæ¹æ³ã§ã¯ãã¡ã¢ãªãªãŒã¯ããªãããšãä¿èšŒããŸãããDisposeïŒïŒã®åŒã³åºããå¿ããããšãã§ããŸãã ããã«ããã€åŒã³åºããã決å®ããããšã¯éåžžã«åé¡ã«ãªãå¯èœæ§ããããŸãã ãŸãã¯ãããæ±ãã«ãããå¹æçãªã¢ãããŒãã§ãã匱ãã€ãã³ããæ€èšããããšãã§ããŸãã å®è£ ã®äžè¬çãªèãæ¹ã¯ãã€ãã³ããœãŒã¹ãšãµãã¹ã¯ã©ã€ãã®éã«ã匱ãããªã³ã¯ã確ç«ããããããžã®ã匷åãªããªã³ã¯ããªããªã£ããšãã«ãµãã¹ã¯ã©ã€ããèªåçã«åé€ã§ããããšã§ãã
Weak Eventsãã¿ãŒã³ã®å®è£ ã®èª¬æã¯ãã®èšäºã®ç¯å²ãè¶ ããŠããããããã®ãããã¯ã詳现ã«è°è«ãããŠãããªã³ã¯ïŒ http://www.codeproject.com/Articles/29922/Weak-Events-in-CïŒãææããŸã ã
ãã€ã³ãã£ã³ã°ãªãŒã¯
äžèšã®æœåšçãªåé¡ã«å ããŠãWPFã«ã¯ããã®ãã¯ãããžã«åºæã®å°ãªããšã2çš®é¡ã®ãªãŒã¯ããããŸãã
åçŽãªãªããžã§ã¯ãããããšããŸãïŒ
public class SomeModelEntity { public string Name { get; set; } }
ãããŠãä»»æã®ã³ã³ãããŒã«ãããã®ããããã£ã«ã¢ã¿ãããããŸãïŒ
<TextBlock Text="{Binding Entity.Name, Mode=OneWay}" />
ãã€ã³ãå ã®ããããã£ãDependencyPropertyã§ã¯ãªãå ŽåããŸãã¯ãããå«ããªããžã§ã¯ããINotifyPropertyChangedãå®è£ ããŠããªãå Žåããã€ã³ãã¡ã«ããºã ã¯System.ComponentModel.PropertyDescriptorã¯ã©ã¹ã®ValueChangedã€ãã³ãã䜿çšããŠå€æŽã远跡ããŸãã ããã§ã®åé¡ã¯ããã¬ãŒã ã¯ãŒã¯ãPropertyDescriptorã®ã€ã³ã¹ã¿ã³ã¹ãžã®åç §ãä¿æããŠããããã®ã€ã³ã¹ã¿ã³ã¹ããœãŒã¹ãªããžã§ã¯ããåç §ããŠããããã®ã€ã³ã¹ã¿ã³ã¹ããã€åé€ã§ããããæ確ã§ãªãããšã§ãã OneTimeãã€ã³ãã£ã³ã°ã®å Žåãå€æŽã远跡ããå¿ èŠããªããããåé¡ã¯é¢ä¿ãªãããšã«æ³šæããŠãã ããã
ãã®åé¡ã«é¢ããæ å ±ã¯ããã€ã¯ããœãããµããŒãæè¡æ å ±ïŒ https://support.microsoft.com/en-us/kb/938416 ïŒã«ãèšèŒãããŠããŸããããªãŒã¯ã«é¢ãã1ã€ã®è¿œå æ¡ä»¶ã瀺ããŠããŸãã åã®äŸã«é©çšãããšãSomeModelEntityã€ã³ã¹ã¿ã³ã¹ã¯ããªãŒã¯ãçºçããããã«çŽæ¥ãŸãã¯éæ¥çã«TextBoxãåç §ããå¿ èŠããããŸãã äžæ¹ã§ããã®æ¡ä»¶ã¯å®éã«ã¯ãã£ãã«æºããããŸããããå®éã«ã¯ãããã¯ãªãŒã³ãªãã¢ãããŒãã«åŸãæ¹ãåžžã«è¯ãã§ã-å€æŽãç£èŠããå¿ èŠããªãå Žåã¯OneTimeãã€ã³ãã£ã³ã°ã¢ãŒããæ瀺çã«ç€ºããããœãŒã¹ãªããžã§ã¯ãã«INotifyPropertyChangedãå®è£ ããããDependencyPropertyããããã£ãèšå®ããŸãïŒèŠèŠã³ã³ããŒãã³ãã®ããããã£ã«ãšã£ãŠæå³ããããŸãïŒã
ãã€ã³ããŒã®ã€ã³ã¹ããŒã«æã«çºçããå¯èœæ§ã®ããå¥ã®åé¡ã¯ãINotifyCollectionChangedã€ã³ã¿ãŒãã§ã€ã¹ãå®è£ ããªãã³ã¬ã¯ã·ã§ã³ã«ãã€ã³ãããããšã§ãã ãã®å Žåã®æŒãã®ã¡ã«ããºã ã¯ãåã®ãã®ãšéåžžã«äŒŒãŠããŸãã ããã«å¯ŸåŠããæ¹æ³ã¯æããã§ããOneTimeãã€ã³ãã£ã³ã°ã¢ãŒããæ瀺çã«æå®ãããããŸãã¯INotifyCollectionChangedãå®è£ ããã³ã¬ã¯ã·ã§ã³ïŒObservableCollectionãªã©ïŒã䜿çšããå¿ èŠããããŸãã
èŠèŠçãªã³ã³ããŒãã³ããšã¹ã¿ã€ã«ã®ç¶æ¿
æ©èœãæ¡åŒµããåäœãå€æŽããããã«ãæšæºã³ã³ãããŒã«ã®ç¶æ¿ãå¿ èŠã«ãªãå ŽåããããŸãã äžèŠãããšãããããã¯åºæ¬çãªãã®ã§ãã
public class CustomComboBox : ComboBox { //⊠}
ããããã¢ããªã±ãŒã·ã§ã³ãããã©ã«ãã®ã¹ã¿ã€ã«ä»¥å€ã®èŠçŽ ã¹ã¿ã€ã«ã䜿çšããŠããå Žåããã®ãããªç¶æ¿ã䜿çšããåé¡ã¯ããã«é¡èã«ãªããŸãã 次ã®ã¹ã¯ãªãŒã³ã·ã§ããã®æçã¯ãPresentationFramework.AeroããŒããæå¹ãªå Žåã®ããŒã¹ã³ã³ãããŒã«ãšæŽŸçç©ã®è¡šç€ºã®éãã瀺ããŠããŸãã
ãããä¿®æ£ããæãç°¡åãªæ¹æ³ã¯ãããŒããªãœãŒã¹ãå«ããåŸãXAMLãã¡ã€ã«ã®ããŒã¹èŠçŽ ããç¶æ¿ããã掟çèŠçŽ ã®ã¹ã¿ã€ã«ãå®çŸ©ããããšã§ãã ããã¯ãBasedOnå±æ§ã䜿çšããŠç°¡åã«å®è¡ã§ããŸãã
<Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="/PresentationFramework.Aero;component/themes/Aero.NormalColor.xaml" /> </ResourceDictionary.MergedDictionaries> <Style TargetType="{x:Type my:CustomComboBox}" BasedOn="{StaticResource {x:Type ComboBox}}"> </Style> </ResourceDictionary> </Application.Resources>
ãããã掟çã³ã³ãããŒã«ã䜿çšããå ŽåããªãœãŒã¹ã«ã¹ã¿ã€ã«ãè¿œå ããããšãåžžã«èŠããŠããå¿ èŠãããããšãããããŸããã ãŸãã¯ããã®æŽŸçã¹ã¿ã€ã«ã§ãã¡ã€ã«ãäœæããæ°ããèŠçŽ ã䜿çšããå¿ èŠããããã³ã«æ·»ä»ããŸãã
XAMLãå€æŽããã«è¡ãæ¹æ³ã1ã€ãããŸã-掟çèŠçŽ ã®ã³ã³ã¹ãã©ã¯ã¿ãŒã§ãããŒã¹èŠçŽ ããååŸããã¹ã¿ã€ã«ãæ瀺çã«èšå®ããŸãã
public CustomComboBox() { SetResourceReference(StyleProperty, typeof(ComboBox)); }
ãããã£ãŠãåºæ¬ã¹ã¿ã€ã«ã«å€æŽãè¿œå ããå¿ èŠããªãå Žåããã®æ¹æ³ãæé©ã§ãã ãã以å€ã®å Žåã¯ãåã®ãªãã·ã§ã³ã䜿çšããããšããå§ãããŸãã
ãã€ã³ããšã©ãŒ
ãã¡ãããã³ã³ãããŒã«ãã¢ãã«ã®ãã£ãŒã«ããšå®£èšçã«ãªã³ã¯ããããšã«ã¯å©ç¹ããããŸããããã®æŽåæ§ãç£èŠããã®ã¯ããã»ã©ç°¡åã§ã¯ãããŸããã äœããã®çç±ã§ãã€ã³ãã£ã³ã°ã§ç€ºãããããããã£ãèŠã€ãããªãå Žåããšã©ãŒã¯ãããã°ãã°ã«æžã蟌ãŸããŸã...ãããŠããã ãã§ãã ããã©ã«ãã§ã¯ããŠãŒã¶ãŒã«ã¯ã¡ãã»ãŒãžã¯è¡šç€ºãããŸãããããããã°ãªãã§èµ·åãããšããããã®ãšã©ãŒã¯ãã°ã«èšé²ãããŸããã
éçºè ããã®ãããªãšã©ãŒãããç®ç«ã€ããã«ããããã«ãã¡ãã»ãŒãžã®åœ¢åŒã§ãšã©ãŒã衚瀺ããç¹å¥ãªãã¬ãŒã¹ãªã¹ããŒãäœæã§ããŸãã
public class BindingErrorTraceListener : TraceListener { private readonly StringBuilder _messageBuilder = new StringBuilder(); public override void Write(string message) { _messageBuilder.Append(message); } public override void WriteLine(string message) { Write(message); MessageBox.Show(_messageBuilder.ToString(), "Binding error", MessageBoxButton.OK, MessageBoxImage.Warning); _messageBuilder.Clear(); } }
ãããŠãã¢ããªã±ãŒã·ã§ã³ã®èµ·åæã«ã¢ã¯ãã£ãã«ããŸãã
PresentationTraceSources.DataBindingSource.Listeners.Add(new BindingErrorTraceListener()); PresentationTraceSources.DataBindingSource.Switch.Level = SourceLevels.Error;
ãããã®å€æŽåŸãåãã€ã³ãã£ã³ã°ãšã©ãŒã¯ãã€ã¢ãã°ã¡ãã»ãŒãžãšããŠè¡šç€ºãããŸããã ãããã°ã§éå§ããå Žåã®ã¿ã§ãããã®ããããã³ãã©ãŒããªãªãŒã¹ããŒãžã§ã³ã«ç»é²ãããªãããã«æ¡ä»¶ä»ãã³ã³ãã€ã«ã䜿çšããã®ãçã«ããªã£ãŠããŸãã
æšæºæ€èšŒããŒã«
WPFã§ããŒã¿ãæ€èšŒããæ¹æ³ã¯ããã€ããããŸãã
ValidationRule-ãã®ã¯ã©ã¹ãç¶æ¿ããXAMLããŒã¯ã¢ããã®ãã£ãŒã«ãã«ãã€ã³ããããç¹å¥ãªæ€èšŒã«ãŒã«ãäœæã§ããŸãã ãæ¡ä»¶ä»ããå©ç¹-æ€èšŒãå®è¡ããããã«ã¢ãã«ã¯ã©ã¹ãå€æŽããå¿ èŠã¯ãããŸããããå Žåã«ãã£ãŠã¯ãããæè¯ã®ãªãã·ã§ã³ã§ã¯ãªãå¯èœæ§ããããŸãã ããããåæã«é倧ãªæ¬ ç¹ããããŸã-ValidationRuleã¯DependencyObjectãç¶æ¿ããªããããçžç¶äººã«ã¯åŸã§ãã€ã³ãã§ããããããã£ãäœæããæ¹æ³ããããŸããã ããã¯ãããšãã°ãäžæ¹ã®å€ãä»æ¹ã®å€ãã倧ããããããšãã§ããªãå Žåãªã©ãããããã£ãçžäºã«æ€èšŒããããã®åçŽã§æçœãªæ¹æ³ããªãããšãæå³ããŸãã ãã®æ¹æ³ã§å®è£ ãããæ€èšŒã«ãŒã«ã¯ããã®ã«ãŒã«ã®ã€ã³ã¹ã¿ã³ã¹ãäœæãããšãã«æå®ãããçŸåšã®ãã£ãŒã«ãå€ãšåºå®ããããã£å€ã®ã¿ãåŠçã§ããŸãã
IDataErrorInfoãINotifyDataErrorInfo-ãããã®ã€ã³ã¿ãŒãã§ã€ã¹ããã¬ãŒã³ããŒã·ã§ã³ã¢ãã«ã®ã¯ã©ã¹ã«å®è£ ãããšãåã ã®ããããã£ãšããã€ãã®ããããã£ã®äž¡æ¹ãç°¡åã«æ€èšŒã§ããŸãã éåžžãã³ãŒãã®éãæžããããã«ããããã®ã€ã³ã¿ãŒãã§ã€ã¹ã®1ã€ã¯ã¢ãã«ã®åºæ¬ã¯ã©ã¹ã«å®è£ ãããçžç¶äººã®ã«ãŒã«ãç°¡æœã«èª¬æããæ段ãæäŸããŸãã ããšãã°ãåã¿ã€ãã®éçã³ã³ã¹ãã©ã¯ã¿ãŒã«ã«ãŒã«ãç»é²ããããšã«ããïŒ
static SomeModelEntity() { RegisterValidator(me => me.Name, me => !string.IsNullOrWhiteSpace(me.Name), Resources.RequiredFieldMessage); }
ãŸãã¯ãå±æ§ãéããŠïŒ
[Required] public string Name { get { return _name; } set { _name = value; NotifyPropertyChanged(); } }
2çªç®ã®ãªãã·ã§ã³ã®èª¬æã¯ã httpïŒ//www.codeproject.com/Articles/97564/Attributes-based-Validation-in-a-WPF-MVVM-Applicatã§ç¢ºèªã§ããŸã ã
ããããDataErrorInfoã€ã³ã¿ãŒãã§ãŒã¹ã䜿çšããã¢ãããŒãã¯ããã¹ãŠã®æ€èšŒã¿ã¹ã¯ãã«ããŒããŠããŸãã-æ€èšŒããããšã³ãã£ãã£ã®å€éšã®ãªããžã§ã¯ãã«ã¢ã¯ã»ã¹ããå¿ èŠãããã«ãŒã«ããã§ãã¯ããå Žåãåé¡ãçºçãå§ããŸãã ããšãã°ãäžææ§ããã§ãã¯ããã«ã¯ããªããžã§ã¯ãã®å®å šãªã³ã¬ã¯ã·ã§ã³ã«ã¢ã¯ã»ã¹ããå¿ èŠããããŸããã€ãŸãããã®ãããªã³ã¬ã¯ã·ã§ã³ã®åèŠçŽ ã«ãªã³ã¯ãèšå®ããå¿ èŠãããããªããžã§ã¯ãã®åŠçãéåžžã«è€éã«ãªããŸãã
æ®å¿µãªãããWPFã«ã¯ãã®åé¡ãç°¡åã«åé¿ããããã®æšæºããŒã«ããªããããç¬èªã®ããŒã«ãäœæããå¿ èŠããããŸãã æãåçŽãªã±ãŒã¹ã§ã¯ãä¿åããåã«ã¬ã³ãŒãã®äžææ§ã確èªããå¿ èŠãããå Žåãä¿åãåŒã³åºãåã«ã³ãŒãã§æ瀺çã«ãããå®è¡ãããšã©ãŒã®å Žåã«ã¡ãã»ãŒãžã衚瀺ã§ããŸãã
å®éããã®ã¢ãããŒãã¯äžè¬åããããšãã§ããŸãã éçã³ã³ã¹ãã©ã¯ã¿ãŒã«ããªããŒã¿ãŒãç»é²ããéã«ãäžèšã®ã¢ã€ãã¢ã䜿çšããŸãã åºæ¬ã¯ã©ã¹ã®äŸã次ã«ç€ºããŸãã
public class ValidatableEntity<TEntity> : IDataErrorInfo { // "" protected static void RegisterValidator<TProperty>( Expression<Func<TProperty>> property, Func<TEntity, bool> validate, string message) { //... } // , - , protected static void RegisterValidatorWithState<TProperty>( Expression<Func<TProperty>> property, Func<TEntity, object, bool> validate, string message) { //... } public bool Validate(object state, out IEnumerable<string> errors) { // . , RegisterValidatorWithState, state . } // IDataErrorInfo, , RegisterValidator }
ãŸãã䜿çšäŸïŒ
public class SomeModelEntity : ValidatableEntity<SomeModelEntity> { public string Name { get; set; } static SomeModelEntity() { RegisterValidator(me => me.Name, me => !string.IsNullOrWhiteSpace(me.Name), Resources.RequiredFieldMessage); RegisterValidatorWithState(me => me.Name, (me, all) => ((IEnumerable<SomeEntity>)all).Any(e => e.Name == me.Name), Resources.UniqueNameMessage); } }
ãããã£ãŠããã¹ãŠã®æ€èšŒã«ãŒã«ã¯ãšã³ãã£ãã£èªäœã®äžã«ãããŸãã ãå€éšããªããžã§ã¯ããå¿ èŠãšããªããã®ã¯ãåºæ¬ã¯ã©ã¹ããã®IDataErrorInfoã®å®è£ ã§äœ¿çšãããŸãã æ®ãã®éšåã確èªããã«ã¯ãé©åãªå Žæã§Validateé¢æ°ãåŒã³åºãããã®çµæã䜿çšããŠããã«ã¢ã¯ã·ã§ã³ã決å®ããã ãã§ååã§ãã
PropertyChangedã€ãã³ãã®èª€çš
ç§ã¯WPFãããžã§ã¯ãã§ãã®çš®ã®ã³ãŒãã«é »ç¹ã«äŒããªããã°ãªããŸããã§ããã
private void someViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == "Quantity") { //- , , , } }
ãããŠå€ãã®å Žåãããã¯ç¬èªã®ã€ãã³ãã®ãã³ãã©ãŒã§ããã 宣èšãããåãã¯ã©ã¹ã®ããããã£ã®å€æŽãããªã¹ãã³ã°ãããŸããã
ãã®ã¢ãããŒãã«ã¯ããã€ãã®é倧ãªæ¬ ç¹ãããããã®çµæããµããŒããšæ¡åŒµã®ç¹ã§éåžžã«é£ããã³ãŒãã«ãªããŸãã ãããã®ããã€ãã¯æããã§ããããšãã°ãããããã£ã®ååãå€æŽãããšããæ¡ä»¶ã®å®æ°ãå€æŽããã®ãå¿ããããšãã§ããŸãããããã¯ãã€ããŒã§ç°¡åã«è§£æ±ºã§ããæ¬ ç¹ã§ãã ããã«æ·±å»ãªåé¡ã¯ããã®ã¢ãããŒãã§ã¯ãç¹å®ã®ããžãã¯ãå®è¡ããããã¹ãŠã®ã·ããªãªã远跡ããããšãã»ãŒäžå¯èœã§ããããšã§ãã
PropertyChangedã€ãã³ããã³ãã©ãŒãæ£ãã䜿çšãããŠãããã©ãããèªå·±ãã§ãã¯ããããã®æ¬¡ã®åºæºãå®åŒåã§ããŸãããã³ãã©ãŒå ã®ã¢ã«ãŽãªãºã ãç¹å®ã®ããããã£åã«äŸåããªãå Žåããã¹ãŠãæ£åžžã§ãã ããã§ãªããã°ãããè¯ã解決çãæ¢ãå¿ èŠããããŸãã æ£ããã¢ããªã±ãŒã·ã§ã³ã®äŸã¯ãããšãã°ããã¥ãŒã¢ãã«ã®ããããã£ãå€æŽãããšãã«IsModifiedããããã£ãtrueã«èšå®ããããšã§ãã
Dispatcherã®éå°äœ¿çš
WPFãããžã§ã¯ãã§ç¹°ãè¿ããUIã¹ã¬ããã§ã®æäœã®åŒ·å¶çãªå®è¡ã«ééããŸããããããå¿ èŠã§ãªãå Žåã§ãã§ãã åé¡ã®èŠæš¡ã説æããããã«ãCore i7-3630QM 2.4GHzããã»ããµãæèŒããã©ãããããã§ç°¡åãªãã¹ãã䜿çšããŠååŸããæ°å€ãããã€ã瀺ããŸãã
- Dispatcherãå±ããåãã¹ããªãŒã ããåŒã³åºããå ŽåãDispatcher.Invokeãããã€ããŒãããè¶ ããŠè²»ããæéã¯ãåŒã³åºãããšã«0.2ÎŒsã§ãã
- åãã€ã³ãžã±ãŒã¿ãŒã§ãããå¥ã®ã¹ã¬ããããåŒã³åºãå Žå-åŒã³åºãããšã«26ÎŒsã
æåã®æ°åã¯æãèŠããŸããããã³ãŒããUIã¹ã¬ããã§å®è¡ãããããšãããã£ãŠããå ŽåãDispatcherãä»ããŠäœããåŒã³åºãããšãééã£ãŠããŸãã ãããã2çªç®ã®å³ã¯ãã§ã«é¡èã«èŠããŸãã ç¹ã«è€æ°ã®äžŠåã¹ã¬ãããããã£ã¹ãããããå Žåãå®éã®è€éãªã¢ããªã±ãŒã·ã§ã³ã§ã¯ããã®æéãã¯ããã«é·ããªãå¯èœæ§ãããããšã«æ³šæããŠãã ããã ãããŠããã匱ãããã€ã¹ã§-ããã«ã
çç£æ§ãžã®å®³ãæžããã«ã¯ãç°¡åãªã«ãŒã«ãå®ãã ãã§ååã§ãã
- ããã¯ã°ã©ãŠã³ãã¹ã¬ããã§å®éã«å®è¡ã§ããªãããšã ãããã£ã¹ãããããŸãã ããšãã°ãWEBãµãŒãã¹ããäœããèªã¿åããã¢ã«ãŽãªãºã ã䜿çšããŠèšç®ãè¡ãããã¬ãŒã³ããŒã·ã§ã³ã¢ãã«ã«ããã€ãã®ããããã£ãèšå®ããã³ãŒãããããŸãã ãã®å Žåãããããã£ã®èšå®ã®ã¿ããã£ã¹ãããããå¿ èŠããããŸãïŒé çªã«ãPropertyChangedãã³ãã©ãŒãåŒã³åºããŸãããã®äžã«ã¯UIã§æ©èœããã³ãŒãããããŸãïŒã
- å éšã§DispatcherãåŒã³åºãã«ãŒããé¿ããŸãã ããšãã°ããµãŒããŒãããªã¹ããèªã¿åããåèŠçŽ ã®ããŒã¿ã«å¿ããŠUIãæŽæ°ããå¿ èŠããããŸãã ãã®å Žåãæåã«UIã§æŽæ°ããå¿ èŠã®ãããã¹ãŠãããã¯ã°ã©ãŠã³ãã¹ã¬ããã§èšç®ãã次ã«Dispatcher.Invokeã1ååŒã³åºããŠæŽæ°ããããšããå§ãããŸãã ãªã¹ãå ã®åã¢ã€ãã ãåŠçããåŸã«InvokeãåŒã³åºãããšã¯ã極ããŠæé©ãªãœãªã¥ãŒã·ã§ã³ã§ã¯ãããŸããã
ã¢ãŒãã«ãã€ã¢ãã°
WPFãããžã§ã¯ãã§æšæºã®ã¢ãŒãã«ã¡ãã»ãŒãžïŒMessageBoxïŒã䜿çšããããšã¯æè¿ãããŸãããã¢ããªã±ãŒã·ã§ã³ã®èŠèŠã¹ã¿ã€ã«ã«åŸã£ãŠå€èŠ³ãã«ã¹ã¿ãã€ãºããããšã¯åã«äžå¯èœã ããã§ãã æšæºã¡ãã»ãŒãžã®ä»£ããã«ãç¬èªã®å®è£ ãäœæããå¿ èŠããããŸããããã¯ãæ¡ä»¶ä»ãã§2ã€ã®ã¿ã€ãã«åããããšãã§ããŸãã
- å¿ èŠã«å¿ããŠæ§åŒåãããå¥åã®ã¢ãŒãã«ãŠã£ã³ããŠïŒWindow.ShowDialogïŒã
- ã¡ã€ã³ãŠã£ã³ããŠã®ããžã¥ã¢ã«ããªãŒã«ããã«ãè¿œå ããããšã«ããã¢ãŒãã«ãŠã£ã³ããŠã®ããšãã¥ã¬ãŒã·ã§ã³ããããã¯ä»ã®ãã¹ãŠã®ã³ã³ãã³ãã®ãäžãã«ãããããã«ãã£ãŠãªãŒããŒã©ããããŸãã
ããããã®ã¢ãããŒãã«ã¯é·æãšçæããããŸãã æåã®ãªãã·ã§ã³ã¯å®è£ ãç°¡åã§ãããã¢ãŒãã«ãã€ã¢ãã°ã衚瀺ããããŠã£ã³ããŠã®ã³ã³ãã³ãå šäœããèæãããããªã©ã®å¹æãå®çŸããããšã¯ã§ããŸããã äžéšã®ã¢ããªã±ãŒã·ã§ã³ã§ã¯ãéæšæºåœ¢åŒã®ãã€ã¢ãã°ãå¿ èŠã«ãªãå ŽåããããŸãããããã¯éåžžã®ãŠã£ã³ããŠã§ã¯ç°¡åã§ã¯ãããŸããã
éåžžã2çªç®ã®ãªãã·ã§ã³ã¯å®è£ ã§å€ãã®åé¡ãåŒãèµ·ãããŸããããã¯ããã®ãããªãŠã£ã³ããŠã®è¡šç€ºãåæã§ããªããšããäºå®ãåå ã§ãã ã€ãŸããéåžžã®ã¡ãã»ãŒãžã®ããã«æžãããšã¯ã§ããŸããã
if (MessageBox.Show(Resources.ResetSettingsQuestion, Resources.ResetSettings, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) {
ãŠãŒã¶ãŒã質åã«çãããŸã§ãã¡ã€ã³ã¹ã¬ããã§ä»ã«äœãèµ·ãããªãããšãæåŸ ããŸãã
ããšãã¥ã¬ãŒããããããã€ã¢ãã°ã®æãåçŽãªå®è£ ã®1ã€ãæ€èšããŠãã ããã
ãŸãããã¬ãŒã³ããŒã·ã§ã³ã¢ãã«ããã€ã¢ãã°ã衚瀺ããããã®ãã€ã¢ãã°ãããŒãžã£ãŒã€ã³ã¿ãŒãã§ã€ã¹ã宣èšããŸãã ããããããŠã£ã³ããŠãããå¿çããåä¿¡ããå¯èœæ§ãèæ ®ããããã€ã¢ãã°ãéãããã¿ã³ã§è¡šç€ºããã ãã§ãã
public interface IModalDialogHelper { public string Text { get; } ICommand CloseCommand { get; } void Show(string text); void Close(); }
次ã«ãå¿ èŠã«å¿ããŠããããŒãžã£ãŒã«ãã¹ããããããæ®ãã®èŠçŽ ã®äžã«ãŠã£ã³ããŠã衚瀺ããã³ã³ãããŒã«ãå®è£ ããŸãã
<UserControl x:Class="TestDialog.ModalDialog" 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" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300" Panel.ZIndex="1000"> <UserControl.Style> <Style TargetType="{x:Type UserControl}"> <Setter Property="Visibility" Value="Collapsed" /> <Style.Triggers> <DataTrigger Binding="{Binding DialogHelper.IsVisible}" Value="True"> <Setter Property="Visibility" Value="Visible" /> </DataTrigger> </Style.Triggers> </Style> </UserControl.Style> <Grid> <Border HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="DarkGray" Opacity=".7" /> <Grid HorizontalAlignment="Stretch" Height="200" Background="AliceBlue"> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <TextBlock Grid.Row="0" Text="{Binding DialogHelper.Text}" /> <Button Grid.Row="1" Content="Close" Command="{Binding DialogHelper.CloseCommand}" HorizontalAlignment="Right" /> </Grid> </Grid> </UserControl>
ç¹°ãè¿ããŸãããåçŽåããããã«ããã®ã³ã³ãããŒã«ã¯ããã¥ãŒã¢ãã«ã®DialogHelperããããã£ã«IModalDialogHelperå®è£ ã®ã€ã³ã¹ã¿ã³ã¹ã確å®ã«å«ãŸããããã«èšèšãããŠããŸããããæ®éçãªãœãªã¥ãŒã·ã§ã³ã§ã¯ãä»»æã®ããããã£ã代çšããããšãå¯èœã§ããã¹ãã§ãã
ããã§ã¯IModalDialogHelperã®æãåçŽãªå®è£ ã®äŸã瀺ããŸãããããã¯æãããªã®ã§ãShowïŒïŒããã³CloseïŒïŒã¡ãœããã¯IsVisibleãèšå®ããCloseCommandã³ãã³ãã¯åã«CloseïŒïŒã¡ãœãããåŒã³åºããŸãã ShowïŒïŒã¯Textããããã£ãèšå®ããŸãã
ãã¹ãŠãã·ã³ãã«ãªããã§ããç®çã®ã¡ãã»ãŒãžããã¹ãã䜿çšããŠShowïŒïŒã¡ãœãããåŒã³åºããã¡ãã»ãŒãžãšãã¿ã³ã衚瀺ãããããã«ã衚瀺ããéãããã¿ã³ãã¯ãªãã¯ãããšIsVisibleãå ã®å€ã«èšå®ãããããã€ã¢ãã°ããç»é¢ããæ¶ããŸãããããããã§ã«æåã®åé¡ããããŸã-ShowïŒïŒã¡ãœããã¯åã®ãã€ã¢ãã°ãéããããšãæåŸ ããŠããªããããããã€ãã®ã¡ãã»ãŒãžãé çªã«è¡šç€ºãããšããŠãŒã¶ãŒã«ã¯æåŸã®ã¡ãã»ãŒãžã®ã¿ã衚瀺ãããŸãã
ãã®åé¡ã解決ããããã«ãShowã¡ãœããã®ãããã¿ã€ãããããã«å€æŽããŸãã
Task Show(string text);
ãã®ã¡ãœãããawaitã§å®äºããã®ãåŸ ã€ããšãã§ãããšãã©ã€ã³ã¹ããŒã³ã«ããã€ãã®å©ç¹ããããŸãã
- åã®äŸãšã¯ç°ãªããåãã¹ããªãŒã ããè€æ°ã®ã¡ãã»ãŒãžãé£ç¶ããŠè¡šç€ºããããšã¯æ£ããæ©èœããŸãã
- ã¡ãœãããå®è£ ããŠãç°ãªãã¹ã¬ããããã¡ãã»ãŒãžãåŒã³åºããŠãæ£ããåäœãããã§ã«è¡šç€ºãããŠãããã€ã¢ãã°ãéããã®ãåŸ ã€ããšãã§ããŸãã
- ãå€ããMessageBox.ShowïŒïŒã®ããã«ãã¢ãŒãã«çµæãè¿ãããšãã§ããŸãã
ããã§ãäžèšã®ãã€ã³ãã«å¯Ÿå¿ããéåæ衚瀺ã䜿çšããŠIModalDialogHelperã€ã³ã¿ãŒãã§ã€ã¹ãå®è£ ããããã®ãªãã·ã§ã³ã®1ã€ãæäŸããŸãïŒãã®å®è£ ã§ã¯ãåãã¢ãŒãã«çµæãåžžã«è¿ãããŸãããæŒããããã¿ã³ã«äŸåããããšã¯é£ãããããŸããïŒã
class ModalDialogHelper : INotifyPropertyChanged, IModalDialogHelper { private readonly Queue<TaskCompletionSource<MessageBoxResult>> _waits = new Queue<TaskCompletionSource<MessageBoxResult>>(); private readonly object syncObject = new object(); private readonly Dispatcher _dispatcher = Dispatcher.CurrentDispatcher; //... public async Task Show(string text) { List<TaskCompletionSource<MessageBoxResult>> previousWaits; TaskCompletionSource<MessageBoxResult> currentWait; lock (syncObject) { // , previousWaits = _waits.ToList(); // currentWait = new TaskCompletionSource<MessageBoxResult>(); _waits.Enqueue(currentWait); } // , foreach (var wait in previousWaits) { await wait.Task; } // _dispatcher.Invoke(() => { Text = text; IsVisible = true; }); await currentWait.Task; } public void Close() { IsVisible = false; TaskCompletionSource<MessageBoxResult> wait; lock (syncObject) { // wait = _waits.Dequeue(); } // wait.SetResult(MessageBoxResult.OK); } //... }
ãã®ãœãªã¥ãŒã·ã§ã³ã®äž»ãªã¢ã€ãã¢ã¯ãShowåŒã³åºãããšã«TaskCompletionSourceã®ã€ã³ã¹ã¿ã³ã¹ãäœæãããããšã§ããå éšã§äœæãããã¿ã¹ã¯ãåŸ ã€ããšã¯ãçµæãSetResultã®åŒã³åºããéããŠæå®ããããŸã§ç¶ããŸãã Showã¯ãã¡ãã»ãŒãžã衚瀺ããåã«ããã§ã«ãã¥ãŒã«ãããã¹ãŠã®ã¿ã¹ã¯ãåŸ æ©ããshowã®åŸãç¬èªã®ã¿ã¹ã¯ãåŸ æ©ããCloseã§çŸåšã®ã¿ã¹ã¯ã®çµæãèšå®ããŠå®äºããŸãã
ãŸããCancelEventHandlerã®ãããªã€ãã³ããã³ãã©ã§ã®ãæ°ããããã€ã¢ãã°ã®äœ¿çšã«ã€ããŠãããã€ãã®èšèãèšãå¿ èŠããããŸãããã®ãããªã€ãã³ãã§ã®ã¢ã¯ã·ã§ã³ã®ç¢ºèªãã以åãšã¯å°ãç°ãªãæ¹æ³ã§å®è£ ããå¿ èŠããããŸãã
// ! private async void Window_Closing(object sender, CancelEventArgs e) { e.Cancel = true; if(await dialogHelper.Show("Do you really want to close the window", MessageBoxButton.YesNo) == MessageBoxResult.Yes) { e.Cancel = false; } }
åé¡ã¯ãawaitã¯ãããŒãåæ¢ãããéåæã¿ã¹ã¯ã®å®äºåŸã«ã¡ãœããå ã®é©åãªå Žæã«ãæ»ããæ©èœãäœæãããããWindow_ClosingãåŒã³åºããã³ãŒãã«å¯ŸããŠe.Cancelãåžžã«trueã«ãªãããšã§ããåŒã³åºãã³ãŒãã®å Žåãe.Cancelãtrueã«èšå®ãããšãWindows_Closingã¯ããã«çµäºããŸãã
æ£ãã解決çã¯ãæ¡ä»¶æ¬äœãe.Cancelã§åäœããªãããã«ããããšã§ãããã ãããã®ãã³ãã©ãŒã®ç¹°ãè¿ãã®åŒã³åºãããã€ãã¹ããŠãè¿œå èŠæ±ãªãã§å®è¡ãããããšãä¿èšŒãããããã«ããã£ã³ã»ã«ãã¢ã¯ã·ã§ã³ãæ瀺çã«åŒã³åºããŸããããšãã°ãããã°ã©ã ã®ã¡ã€ã³ãŠã£ã³ããŠãéããŠããå Žåãã¢ããªã±ãŒã·ã§ã³å šäœãçµäºããæ瀺çãªåŒã³åºãã§ããå¯èœæ§ããããŸãã
ãã£ã¹ãã¬ã€ããã©ãŒãã³ã¹åæ
å€ãã®éçºè ã¯ãããããã¡ã€ã©ãŒããäœã§ããããç¥ã£ãŠãããã¢ããªã±ãŒã·ã§ã³ã®ããã©ãŒãã³ã¹ãåæããã¡ã¢ãªæ¶è²»ãåæããããã«å©çšå¯èœãªããŒã«ãç¥ã£ãŠããŸããããããWPFã¢ããªã±ãŒã·ã§ã³ã§ã¯ãããã»ããµã®è² è·ã®äžéšã¯ãããšãã°XAMLããŒã¯ã¢ããåŠçã¡ã«ããºã ïŒè§£æãããŒã¯ã¢ãããæç»ïŒããçããŸãã ãæšæºã®ããããã¡ã€ã©ãŒããã©ã®XAMLé¢é£ã®ã¢ã¯ãã£ããã£ãªãœãŒã¹ãæ¶è²»ãããŠããããæ£ç¢ºã«å€æããããšã¯å®¹æã§ã¯ãããŸããã
æ¢åã®ããŒã«ã®æ©èœã«ã€ããŠã¯èª¬æãããåã«ãããã«é¢ããæ å ±ãžã®ãªã³ã¯ããªã¹ãããŸãããããã®äœ¿çšæ¹æ³ãèŠã€ããããšã¯ãã©ã®éçºè ã«ãšã£ãŠãç°¡åã§ãã
- WPF Visual Studio 2015 â http://blogs.msdn.com/b/wpf/archive/2015/01/16/new-ui-performance-analysis-tool-for-wpf-applications.aspx
- Visual Studio WPF Performance Suite â https://msdn.microsoft.com/en-us/library/aa969767%28v=vs.110%29.aspx
INotifyPropertyChanged
WPFãã¯ãããžã§æã人æ°ã®ããèšè«ãããã¯ã®1ã€ã¯ãINotifyPropertyChangedãæãåççã«å®è£ ããæ¹æ³ã§ããAspect Injectorã«é¢ããèšäºã® 1ã€ã®äŸã§æ¢ã«èª¬æããããã«ãæãç°¡æœãªãªãã·ã§ã³ã¯AOPã䜿çšããããšã§ãããããã誰ãããã®ã¢ãããŒãã奜ãããã§ã¯ãªããã¹ããããã代æ¿æ段ãšããŠäœ¿çšã§ããŸããããããããã§ã¯ãæé©ãªã¹ããããã³ã³ãã³ãã®åé¡ãçºçããŸããæåã«ãæãæåãããªãã·ã§ã³ã§ã¯ãªãäŸã瀺ããŸãã
private string _name; public string Name { get { return _name; } set { _name = value; NotifyPropertyChanged("Name"); } }
ãã®å Žåãããããã£ã®ååã¯å®æ°ã§ç€ºãããååä»ãå®æ°ã§ããããäŸã®ããã«éç¥ã¡ãœããã®åŒã³åºãã§çŽæ¥ããŒãã³ãŒããããŠãããã©ããã¯é¢ä¿ãããŸãããåé¡ã¯åããŸãŸã§ããããããã£èªäœã®ååãå€æŽãããšãå®æ°ã®å€ãå€ãæ®ãå¯èœæ§ããããŸã å€ãã®äººãNotifyPropertyChangedã¡ãœãããå€æŽããããšã§ãã®åé¡ã解決ããŠããŸãïŒ
public void NotifyPropertyChanged<T>(Expression<Func<T>> property) { var handler = PropertyChanged; if(handler != null) { string propertyName = ((MemberExpression)property.Body).Member.Name; handler(this, new PropertyChangedEventArgs(propertyName)); } }
ãã®å Žåãååã®ä»£ããã«ãç®çã®ããããã£ãè¿ãã©ã ãåŒãæå®ã§ããŸãã
NotifyPropertyChanged(() => Name);
æ®å¿µãªããããã®ãªãã·ã§ã³ã«ã¯æ¬ ç¹ããããŸãããã®ã¡ãœããã®åŒã³åºãã¯åžžã«Reflectionã«é¢é£ä»ããããŸããããã¯ã以åã®NotifyPropertyChangedãªãã·ã§ã³ãåŒã³åºããããæ°çŸåé ãã§ããã¢ãã€ã«ã¢ããªã±ãŒã·ã§ã³ã®å Žåãããã¯éèŠã§ãã
.NET 4.5ã§ã¯ãç¹å¥ãªå±æ§CallerMemberNameAttributeã䜿çšå¯èœã«ãªããŸãããããã«ãããäžèšã®åé¡ã®æåã®åé¡ã解決ã§ããŸãã
public void NotifyPropertyChanged([CallerMemberName] string propertyName = null) { //... } public string Name { get { return _name; } set { _name = value; NotifyPropertyChanged(); } }
ãã®å±æ§ã§ããŒã¯ããããã©ã¡ãŒã¿ãŒãæ瀺çã«æå®ãããŠããªãå Žåãã³ã³ãã€ã©ãŒã¯ã¡ãœãããåŒã³åºãã¯ã©ã¹ã¡ã³ããŒã®ååã«çœ®ãæããŸãããããã£ãŠãäžèšã®äŸããNotifyPropertyChangedïŒïŒãåŒã³åºãããšã¯ãNotifyPropertyChangedïŒâ NameâïŒãšåçã§ããããããããããã£ã®å€æŽãã»ãã¿ãŒããã§ã¯ãªããå€éšãã«å ±åããå¿ èŠãããå Žåã¯ã©ãã§ããããã
ããšãã°ããèšç®ããããããããã£ããããŸãã
public int TotalPrice { get { return items.Sum(i => i.Price); } }
ã¢ã€ãã ã³ã¬ã¯ã·ã§ã³ã®ã¢ã€ãã ãè¿œå ãåé€ããŸãã¯å€æŽããå ŽåããŠãŒã¶ãŒã€ã³ã¿ãŒãã§ã€ã¹ã«åžžã«çŸåšã®å€ã衚瀺ãããããã«ãTotalPriceã«å€æŽãå ±åããå¿ èŠããããŸããäžèšã®æåã®2ã€ã®ãœãªã¥ãŒã·ã§ã³ã®æ¬ ç¹ãèãããšã次ã®åããããããšãã§ããŸã-ãŸã Reflectionã䜿çšããŠã©ã ãåŒããããããã£åãååŸããŸãããéçå€æ°ã«ä¿åããŸãããããã£ãŠãåã ã®ããããã£ããšã«ããéããæäœã¯1åã ãå®è¡ãããŸãã
public class ResultsViewModel : INotifyPropertyChanged { public static readonly string TotalPricePropertyName = ExpressionUtils.GetPropertyName<ResultsViewModel>(m => m.TotalPrice); //... NotifyPropertyChanged(TotalPricePropertyName); //... } public static class ExpressionUtils { public static string GetPropertyName<TEntity>(Expression<Func<TEntity, object>> property) { var convertExpression = property.Body as UnaryExpression; if(convertExpression != null) { return ((MemberExpression)convertExpression.Operand).Member.Name; } return ((MemberExpression)property.Body).Member.Name; } }
éçé¢æ°GetPropertyNameèªäœãããã¹ãŠã®ãéç¥å¯èœãªããšã³ãã£ãã£ã®åºæ¬ã¯ã©ã¹ã«å ¥ããããšãã§ããŸã-ããã¯éèŠã§ã¯ãããŸãããé¢æ°ãéåžžãéèŠãªã¿ã€ãã®ããããã£ãåŠçããããã«ãUnaryExpressionã®ãã§ãã¯ãå¿ èŠã§ããã³ã³ãã€ã©ã¯ãã¯ã·ã³ã°æäœãè¿œå ããŠãæå®ãããããããã£ããªããžã§ã¯ãã«ãã£ã¹ãããŸãã
ãããžã§ã¯ãã§ãã§ã«CïŒ6.0ã䜿çšããŠããå Žåãå¥ã®ããããã£ã®ååãååŸããåãã¿ã¹ã¯ããããŒã¯ãŒãnameofã䜿çšããŠã¯ããã«ç°¡åã«è§£æ±ºã§ããŸããååãèšæ¶ããéçå€æ°ã¯ããå¿ èŠãããŸããã
ãã®çµæãäœããã®çç±ã§INotifyPropertyChangedã«AOPã䜿çšããã®ãé©åã§ãªãå Žåã次ã®ã³ã³ãã³ãã®ã¹ããããã䜿çšã§ãããšèšããŸãã
- .NET 4.5 â , GetPropertyName, . A c, , NotifyPropertyChanged .
- .NET 4.5 â CallerMemberNameAttribute. , â , nameof, C# 6.0.
ããšããã®ä»£ããã«
WPFã¯ããã€ã¯ããœãããããã¹ã¯ããããã¢ããªã±ãŒã·ã§ã³ãéçºããããã®äž»èŠãªãã¬ãŒã ã¯ãŒã¯ãšããŠäœçœ®ä»ãç¶ããŠããåªãããã¯ãããžãŒã§ããæ®å¿µãªããããèšç®æ©ããããè€éãªããã°ã©ã ãäœæãããšãäžèŠããŠç®ç«ããªãå€ãã®åé¡ãçºèŠãããŸããããããã¯ãã¹ãŠè§£æ±ºãããŸãããã€ã¯ããœããã«ããæè¿ã®å£°æã«ãããšã圌ãã¯ãã¯ãããžãŒã®éçºã«æè³ããŠãããæ°ããããŒãžã§ã³ã«ã¯ãã§ã«å€ãã®æ¹åããããŸããäž»ã«ããŒã«ãšããã©ãŒãã³ã¹ã«é¢é£ããŠããŸããå°æ¥ãããŒã«ã ãã§ãªããã¬ãŒã ã¯ãŒã¯èªäœã«ãæ°ããæ©èœãè¿œå ãããããã°ã©ãã®äœæ¥ã容æã«ãªããä»ãããªããã°ãªããªããããã¯ãããèªè»¢è»ãããªããªãããšãé¡ã£ãŠããŸãã
UPDïŒãããžã¥ã¢ã«ã³ã³ããŒãã³ããšã¹ã¿ã€ã«ã®ç¶æ¿ãã»ã¯ã·ã§ã³ã®2çªç®ã®ãœãªã¥ãŒã·ã§ã³ãã³ã¡ã³ãããããæé©ãªãã®ã«å€æŽããCïŒ6.0
UPD2ã® nameofïŒïŒããINotifyPropertyChangedã®ã»ã¯ã·ã§ã³ã«ãœãªã¥ãŒã·ã§ã³ãè¿œå ããŸããã