将Calburn.Micro与扩展WPF工具包结合使用



我正在使用扩展WPF工具包中的IntegerUpDown控件,我也在使用Caliburn.Micro和PostSharp。我试图让它根据ViewModel中的属性设置控件的最大值和最小值。

我可以使用最小值或最大值,但不能同时使用这两个值。所以我显然在做一些只允许最后一个属性绑定保持不变的事情。这是我的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);
        }
    }
}

我发现

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);
                };
        }
    }
}

相关内容

  • 没有找到相关文章

最新更新