wpf 如何在属性设置器中大写文本表达式?

bnlyeluc  于 2023-10-22  发布在  其他
关注(0)|答案(2)|浏览(129)

我正在开发一个C# WPF项目。在View端,名为NewBook的属性绑定到ViewModel端的文本框。但是,我在这个属性的setter中所做的更改并没有反映在视图端。当文本框失去键盘焦点时,我想用ConverToTitle方法将字符串表达式大写。但我想通过NewBook来实现这一点,而不是通过定义单个属性。我的错误在哪里,我如何才能做到这一点?谢谢.

internal class NewBookViewModel : ObservableObject
    {
        LibraryDataContext Db;
                    
        public RelayCommand SaveCommand { get; private set; }
        public RelayCommand CloseWindowCommand { get; }

        private Book _newBook;
        public Book NewBook
        {
get { return _newBook; }
            set
            {
                SetProperty(ref _newBook, value);
                NewBook.ConvertToTitle();
                        }
        }

        private int _demirbasNo;
                public int DemirbasNo
        {
            get { return _demirbasNo; }
            set
            {
                SetProperty(ref _demirbasNo, value);
                NewBook.Barkod = Barcode.GenerateEAN13BarcodeNumber(_demirbasNo);
                NewBook.DemirbasNo = _demirbasNo;                
            }
        }

        private Author Author;
        private Yayinevi publisher;
        public ObservableCollection<Book> BooklarCollection { get; set; }

        public NewBookViewModel()
        {
            SaveCommand = new RelayCommand(SaveExecute, CanExecuteSaveCommand);
            CloseWindowCommand = new RelayCommand(CloseExecute);
            Db = new LibraryDataContext();

NewBook = new Book();
            DemirbasNo= BookService.NextDemirbaşNo();
            NewBook.Barkod = Barcode.GenerateEAN13BarcodeNumber(_demirbasNo);
        }

        private bool CanExecuteSaveCommand() => true;
        
        private void SaveExecute()
        {
            BookValidator validator= new BookValidator();
            ValidationHelper<Book> validationHelper = new ValidationHelper<Book>(validator);
            MessagePublisher.SendMessage(validationHelper.ErrorMessage(NewBook),MessageType.Error);
                  
            /* AuthorCheck(newBook.Authori.AdiSoyadi);
PublisherCheck(newBook.Yayinevi.Adi);
            BookService<Book> BookService = new BookService<Book>();
            BookService.Add(newBook);
            BookService.SaveChanges();
            
            CloseExecute(); */
        }
      
        private void  CloseExecute()
        {
            var activeWindow = Application.Current.Windows.OfType<BaseWindow>().SingleOrDefault(w => w.IsActive);
            if (activeWindow != null)
            {
                activeWindow.Close();
            }

        }
    }

public static void ConvertToTitle<t>(this t obj)
        {
PropertyInfo[] propertyInfo = typeof(t).GetProperties();
            
            foreach (var property in propertyInfo)
            {
                if (property.PropertyType == typeof(string))
                {
                    string value = (string)property.GetValue(obj);
                    if (!string.IsNullOrEmpty(value))
                    {
                        property.SetValue(obj, CultureInfo.CurrentCulture.TextInfo.ToTitleCase(value));
                    }
                                    }                
            }
                    }
    }

internal class NewBookViewModel : ObservableObject
{
LibraryDataContext Db;

public RelayCommand SaveCommand { get; private set; }
public RelayCommand CloseWindowCommand { get; }

private Book _newBook;
public Book NewBook
{
get { return _newBook; }
set
{
SetProperty(ref _newBook, value);
NewBook.ConvertToTitle();
}
}

private int _demirbasNo;
public int DemirbasNo
{
get { return _demirbasNo; }
set
{
SetProperty(ref _demirbasNo, value);
NewBook.Barkod = Barcode.GenerateEAN13BarcodeNumber(_demirbasNo);
NewBook.DemirbasNo = _demirbasNo;
}
}

private Author Author;
private Yayinevi publisher;
public ObservableCollection<Book> BooklarCollection { get; set; }

public NewBookViewModel()
{
SaveCommand = new RelayCommand(SaveExecute, CanExecuteSaveCommand);
CloseWindowCommand = new RelayCommand(CloseExecute);
Db = new LibraryDataContext();

NewBook = new Book();
DemirbasNo= BookService.NextDemirbaşNo();
NewBook.Barkod = Barcode.GenerateEAN13BarcodeNumber(_demirbasNo);
}

private bool CanExecuteSaveCommand() => true;

private void SaveExecute()
{
BookValidator validator= new BookValidator();
ValidationHelper<Book> validationHelper = new ValidationHelper<Book>(validator);
MessagePublisher.SendMessage(validationHelper.ErrorMessage(NewBook),MessageType.Error);

/* AuthorCheck(newBook.Authori.AdiSoyadi);
PublisherCheck(newBook.Yayinevi.Adi);
BookService<Book> BookService = new BookService<Book>();
BookService.Add(newBook);
BookService.SaveChanges();

CloseExecute(); */
}

private voidCloseExecute()
{
var activeWindow = Application.Current.Windows.OfType<BaseWindow>().SingleOrDefault(w => w.IsActive);
if (activeWindow != null)
{
activeWindow.Close();
}

}
}

public static void ConvertToTitle<t>(this t obj)
{
PropertyInfo[] propertyInfo = typeof(t).GetProperties();

foreach (var property in propertyInfo)
{
if (property.PropertyType == typeof(string))
{
string value = (string)property.GetValue(obj);
if (!string.IsNullOrEmpty(value))
{
property.SetValue(obj, CultureInfo.CurrentCulture.TextInfo.ToTitleCase(value));
}
}
}
}
}
jutyujz0

jutyujz01#

你需要你的类继承INotifyPropertyChanged并在setter中调用PropertyChanged事件。类似下面的东西:

public class Library: INotifyPropertyChanged
  {
      private string name;
      // Declare the event
      public event PropertyChangedEventHandler PropertyChanged;

      public Library()
      {
      }

      public Library(string value)
      {
          this.name = value;
      }

      public string Book
      {
          get { return name; }
          set
          {
              name = value;
              // Change to upper case here
              // Call OnPropertyChanged whenever the property is updated
              OnPropertyChanged();
          }
      }

      // Create the OnPropertyChanged method to raise the event
      // The calling member's name will be used as the parameter.
      protected void OnPropertyChanged([CallerMemberName] string name = null)
      {
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
      }
  }
enxuqcxy

enxuqcxy2#

必须为已更改的属性引发INotifyPropertyChanged.PropertyChanged事件,才能更新数据绑定。
首先,确保您的数据源(在本例中为Book)实现了INotifyPropertyChanged
第二,在修改属性后立即引发事件:

public static void ConvertToTitleCase(this INotifyPropertyChanged obj)
{
  Type callerTypeInfo = obj.GetType();
  FieldInfo propertyChangedEventFieldInfo = callerTypeInfo.GetField(nameof(System.ComponentModel.INotifyPropertyChanged.PropertyChanged));
  object eventDelegate = propertyChangedEventFieldInfo.GetValue(obj);
  Type eventDelegateTypeInfo = eventDelegate.GetType();
  MethodInfo delegateInvokeMethodInfo = eventDelegateTypeInfo.GetMethod("Invoke");

  PropertyInfo[] propertyInfo = callerTypeInfo.GetProperties();
  foreach (var property in propertyInfo)
  {
    if (property.PropertyType == typeof(string))
    {
      string value = (string)property.GetValue(obj);
      if (string.IsNullOrEmpty(value))
      {
        return;
      }
      
      property.SetValue(obj, CultureInfo.CurrentCulture.TextInfo.ToTitleCase(value));
      /* Raise the PropertyChanged event for the current property */
  
      string propertyName = property.Name;
      Type propertyChangedEventArgsTypeInfo = typeof(System.ComponentModel.PropertyChangedEventArgs);
      ConstructorInfo propertyChangedEventArgsConstructorInfo = propertyChangedEventArgsTypeInfo.GetConstructor(new[] { typeof(string) });
            
      object propertyChangedEventArgsInstance = propertyChangedEventArgsConstructorInfo.Invoke(obj, new[] { propertyName });
      object sender = obj;
      delegateInvokeMethodInfo.Invoke(eventDelegate, new[] { sender, propertyChangedEventArgsInstance });
    }  
  }
}

备注

  • 您应该避免为object类型编写扩展方法,因为这会使API和代码建议列表变得混乱。因为 * 每个 * .NET类型都继承自object,所以所有对象都可以访问它,即使它没有意义。在此上下文中,泛型类型参数也是多余的,因此此方法不能是泛型方法。

考虑使用更严格的类型,例如以INotifyPropertyChanged开头。因为我们需要引发INotifyPropertyChanged.PropertyChanged事件,所以INotifyPropertyChanged是使代码工作所需的最小类型约束:

public static void ConvertToTitleCase(this INotifyPropertyChanged iNotifyPropertyChangedImplementation)
  • 考虑直接在相关类型中实现字符大小写修改。这消除了缓慢而繁重的反射,并为您的代码增加了清晰度和健壮性:
class Book : INotifyPropertyChanged
{
  private string title;
  public string Title
  {
    get => this.title;
    set
    {
      this.title = ToTitleCase(value);
    }
  }

  public string ToTitleCase(string text)
    => string.IsNullOrWhiteSpace(text)
        ? string.Empty
        : CultureInfo.CurrentCulture.TextInfo.ToTitleCase(text);
}

相关问题