Используя Calburn.Micro с расширенным инструментарием WPF?
Я использую IntegerUpDown
контроль из расширенного инструментария WPF, и я также использую Caliburn.Micro и PostSharp. Я пытаюсь получить его, чтобы установить максимальные и минимальные значения для элемента управления на основе свойств в моей модели представления.
Я могу заставить работать значения Minumum или Maximum, но не оба. Поэтому я, очевидно, делаю что-то, что позволяет привязывать только последнее свойство. Вот мой AppBootstrapper
учебный класс:
using Caliburn.Micro;
using System.Windows;
using Xceed.Wpf.Toolkit;
namespace Test {
public class AppBootstrapper : Bootstrapper<MainViewModel>{
static AppBootstrapper() {
var baseBindProperties = ViewModelBinder.BindProperties;
ConventionManager.AddElementConvention<FrameworkElement>(IntegerUpDown.MinimumProperty, "Minimum", "ValueChanged");
ViewModelBinder.BindProperties =
(frameWorkElements, viewModels) => {
foreach (var frameworkElement in frameWorkElements) {
var propertyName = frameworkElement.Name + "Minimum";
var property = viewModels
.GetPropertyCaseInsensitive(propertyName);
if (property != null) {
var convention = ConventionManager
.GetElementConvention(typeof(FrameworkElement));
ConventionManager.SetBindingWithoutBindingOverwrite(
viewModels,
propertyName,
property,
frameworkElement,
convention,
convention.GetBindableProperty(frameworkElement));
}
}
return baseBindProperties(frameWorkElements, viewModels);
};
ConventionManager.AddElementConvention<FrameworkElement>(IntegerUpDown.MaximumProperty, "Maximum", "ValueChanged");
ViewModelBinder.BindProperties =
(frameWorkElements, viewModels) => {
foreach (var frameworkElement in frameWorkElements) {
var propertyName = frameworkElement.Name + "Maximum";
var property = viewModels
.GetPropertyCaseInsensitive(propertyName);
if (property != null) {
var convention = ConventionManager
.GetElementConvention(typeof(FrameworkElement));
ConventionManager.SetBindingWithoutBindingOverwrite(
viewModels,
propertyName,
property,
frameworkElement,
convention,
convention.GetBindableProperty(frameworkElement));
}
}
return baseBindProperties(frameWorkElements, viewModels);
};
}
}
}
В приведенном выше примере установлено максимальное значение, но не минимальное. Если я поменяю их местами так, чтобы минимальная привязка была установлена последней, минимальная работает, а максимальная - нет. Что я здесь не так делаю?
Для полноты картины, если вы хотите запустить это, вот MainView.xaml:
<Window x:Class="Test.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<TextBox Name="Text"/>
<xctk:IntegerUpDown Name="Number"/>
<Button Name="Click" Height="25" Content="Test"/>
</StackPanel>
</Window>
и MainViewModel.cs:
using Caliburn.Micro;
using PostSharp.Patterns.Model;
using System;
namespace Test {
[NotifyPropertyChanged]
public class MainViewModel : Screen {
public string Text { get; set; }
public int Number { get; set; }
public int NumberMaximum { get; set; }
public int NumberMinimum { get; set; }
public MainViewModel()
: base() {
this.NumberMinimum = 50;
this.NumberMaximum = 100;
this.Number = 75;
}
public void Click() {
Console.WriteLine("Text: '"+this.Text+"'");
Console.WriteLine("Number: '"+this.Number+"'");
}
protected void OnPropertyChanged(string propertyName) {
NotifyOfPropertyChange(propertyName);
}
}
}
1 ответ
Я понял, что
ConventionManager.GetElementConvention(typeof(FrameworkElement));
на самом деле не возвращал правильное соглашение, а вместо этого всегда возвращал последнее добавленное соглашение. Я также думаю, что я настраивал их не в том месте в статическом конструкторе. Поэтому я переместил его в переопределенный Configure
метод. мой AppBootstrapper
класс теперь выглядит так:
using Caliburn.Micro;
using System.Windows;
using Xceed.Wpf.Toolkit;
namespace Test {
public class AppBootstrapper : Bootstrapper<MainViewModel>{
protected override void Configure() {
base.Configure();
//setup the conventions
var valueConvention = ConventionManager.AddElementConvention<FrameworkElement>(IntegerUpDown.ValueProperty, "Value", "ValueChanged");
var maximumConvention = ConventionManager.AddElementConvention<FrameworkElement>(IntegerUpDown.MaximumProperty, "Maximum", "ValueChanged");
var minimumConvention = ConventionManager.AddElementConvention<FrameworkElement>(IntegerUpDown.MinimumProperty, "Minimum", "ValueChanged");
//bind the properties
var baseBindProperties = ViewModelBinder.BindProperties;
ViewModelBinder.BindProperties =
(frameWorkElements, viewModels) => {
foreach (var frameworkElement in frameWorkElements) {
var valuePropertyName = frameworkElement.Name;
var valueProperty = viewModels
.GetPropertyCaseInsensitive(valuePropertyName);
if (valueProperty != null) {
ConventionManager.SetBindingWithoutBindingOverwrite(
viewModels,
valuePropertyName,
valueProperty,
frameworkElement,
valueConvention,
valueConvention.GetBindableProperty(frameworkElement));
}
var maxPropertyName = frameworkElement.Name + "Maximum";
var maxProperty = viewModels
.GetPropertyCaseInsensitive(maxPropertyName);
if (maxProperty != null) {
ConventionManager.SetBindingWithoutBindingOverwrite(
viewModels,
maxPropertyName,
maxProperty,
frameworkElement,
maximumConvention,
maximumConvention.GetBindableProperty(frameworkElement));
}
var minPropertyName = frameworkElement.Name + "Minimum";
var minProperty = viewModels
.GetPropertyCaseInsensitive(minPropertyName);
if (minProperty != null) {
ConventionManager.SetBindingWithoutBindingOverwrite(
viewModels,
minPropertyName,
minProperty,
frameworkElement,
minimumConvention,
minimumConvention.GetBindableProperty(frameworkElement));
}
}
return baseBindProperties(frameWorkElements, viewModels);
};
}
}
}