WPF 之 Binding 对数据的校验与转换(三)

例如:我们把一个 Slider 的Value 属性和 TextBox 的 Text 属性双向绑定在一起, Slider 的Value 的有效值是 0~100。当我们使用 Binding 绑定数值时,需要对该 Binding 的 ValidationRules 添加校验规则。具体实现如下所示:

第一步:我们声明一个 RangeValidationRule 类编写校验规则,该类需要继承 ValidationRule 类(该类为抽象类),ValidationRule类的作用是提供创建自定义规则的一个方式,旨在检查用户输入的有效性。具体代码如下:

  public class RangeValidationRule : ValidationRule

    {

        public override ValidationResult Validate(object value, CultureInfo cultureInfo)

        {

            if (double.TryParse(value.ToString(), out var d))

            {

                if (d >= 0 && d <= 100)

                {

                    return new ValidationResult(true, null);

                }

            }

            return new ValidationResult(false, "Validation value");

        }

    }

第二步:对 TextBox 的 Text 属性进行 Binding 绑定,并对该 Binding 的 ValidationRules 添加一个校验规则 RangeValidationRule 类,具体实现如下:

    <StackPanel Grid.Row="0">

          <TextBox x:Name="TextBox0" Margin="5" Height="50" VerticalContentAlignment="Center" ToolTip="{Binding ElementName=TextBox0,Path=e}">

              <TextBox.Text>

                  <Binding ElementName="Slider0" Path="Value" UpdateSourceTrigger="PropertyChanged">

                      <Binding.ValidationRules>

                          <local:RangeValidationRule ></local:RangeValidationRule>

                      </Binding.ValidationRules>

                  </Binding>

              </TextBox.Text>

          </TextBox>

            <Slider x:Name="Slider0" Margin="5" Minimum="0" Maximum="100"></Slider>

      </StackPanel>

然后,我们在文本框中,输入200,发现 TextBox 会显示红色边框,这表示数值是错误的,具体显示如下图:

image-20210205151612353

三、Binding 的数据转换#

例如:我们实现如下一个程序,程序的用途是在列表里向玩家显示一些军用飞机的状态。数据类型如下:

  public enum Category

    {

        Bomber,

        Fighter,

    }

    public enum State

    {

        Available,

        Locked,

        Unknown,

    }

    public class Plane

    {

        public Category Category { get; set; }

        public string Name { get; set; }

        public State State { get; set; }

    }

在UI中,Plane 的 Category 属性被映射为图片,State 被映射为 CheckBox 的 IsChecked 属性。具体转换规则如下:

public class CategoryToSourceConverter : IValueConverter

    {

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

        {

            var c = (Category)value;

            switch (c)

            {

                case Category.Bomber:

                    return "image/bomber.png";

                case Category.Fighter:

                    return "image/fighter.png";

            }

            return new ValidationResult(false, "Validation Value");

        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

        {

            throw new NotImplementedException();

        }

    }

    public class StateToBoolConverter : IValueConverter

    {

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

        {

            var s = (State) value;

            switch (s)

            {

                case State.Available:

                    return true;

                case State.Locked:

                    return false;

                default:

                    return null;

            }

        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

        {

            var b = (bool?) value;

            switch (b)

            {

                case true:

                    return State.Available;

                case false:

                    return State.Locked;

                default:

                    return State.Unknown;

            }

        }

    }

我们添加一个 ViewModel 绑定到 UI 上,ViewModel 代码如下(属性变更可以阅读 WPF 之 INotifyPropertyChanged 接口的使用 (一)):

public class Window3VM : NotifyProperty

    {

        private ObservableCollection<Plane> _planes;

        private string _output;

        public ObservableCollection<Plane> Planes

        {

            get => _planes;

            set => SetProperty(ref _planes, value);

        }

        public string Output

        {

            get => _output;

            set => SetProperty(ref _output, value);

        }

    }

我们把 ViewModel 绑定到 UI 界面上,并把转换规则添加到对应的 Binding 上,具体实现如下:

<Window x:Class="UI.Window3"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

        xmlns:local="clr-namespace:UI"

        mc:Ignorable="d"

        d:DataContext="{d:DesignInstance local:Window3VM}"

        Title="Window3" Height="500" Width="600">

    <Window.Resources>

      <local:CategoryToSourceConverter x:Key="CTS"></local:CategoryToSourceConverter>

        <local:StateToBoolConverter x:Key="STB"></local:StateToBoolConverter>

    </Window.Resources>

  <Grid>

      <Grid.RowDefinitions>

          <RowDefinition Height="100"></RowDefinition>

          <RowDefinition Height="*"></RowDefinition>

      </Grid.RowDefinitions>

      <StackPanel Grid.Row="0">

          <TextBox x:Name="TextBox0" Margin="5" Height="50" VerticalContentAlignment="Center" ToolTip="{Binding ElementName=TextBox0,Path=e}">

              <TextBox.Text>

                  <Binding ElementName="Slider0" Path="Value" UpdateSourceTrigger="PropertyChanged">

                      <Binding.ValidationRules>

                          <local:RangeValidationRule ></local:RangeValidationRule>

                      </Binding.ValidationRules>

                  </Binding>

              </TextBox.Text>

          </TextBox>

            <Slider x:Name="Slider0" Margin="5" Minimum="0" Maximum="100"></Slider>

      </StackPanel>

        <Grid Grid.Row="1">

          <Grid.ColumnDefinitions>

              <ColumnDefinition Width="*"></ColumnDefinition>

              <ColumnDefinition Width="200"></ColumnDefinition>

          </Grid.ColumnDefinitions>

          <StackPanel Grid.Column="0" Margin="10">

              <ListBox Margin="5" Height="200" ItemsSource="{Binding Path=Planes}">

                  <ListBox.ItemTemplate>

                      <DataTemplate>

                          <StackPanel Orientation="Horizontal">

                              <Image Margin="0,2,0,2" Width="50" Source="{Binding Path=Category,Converter={StaticResource CTS}}"></Image>

                              <TextBlock Margin="0,2,0,2" Width="200" TextAlignment="Center" VerticalAlignment="Center" Text="{Binding Path=Name}"></TextBlock>

                              <CheckBox Margin="0,2,0,2" Width="20"  IsChecked="{Binding Path=State,Converter={StaticResource STB}}"></CheckBox>

                          </StackPanel>

                      </DataTemplate>

                  </ListBox.ItemTemplate>

              </ListBox>

              <Button  Margin="5" Height="50" Content="Load" Click="ButtonLoad_OnClick"></Button>

              <Button Margin="5" Height="50" Content="Save" Click="ButtonSave_OnClick"></Button>

          </StackPanel>

          <StackPanel Grid.Column="1">

              <TextBlock Margin="5,5,5,0" Text="Output Data:"></TextBlock>

              <TextBox x:Name="TextBox" Margin="5" Height="310" BorderBrush="Black" Text="{Binding Path=Output}"></TextBox>

          </StackPanel>

      </Grid>

    </Grid>

</Window>

如下所示,当我们点击Load 按钮后,加载出来列表,点击 Save 按钮后,把整个列表输出到右边的文本框:

/// <summary>

    /// Window3.xaml 的交互逻辑

    /// </summary>

    public partial class Window3 : Window

    {

        private readonly Window3VM vm;

        public Window3()

        {

            InitializeComponent();

            this.DataContext= vm =new Window3VM();

        }

        private void ButtonLoad_OnClick(object sender, RoutedEventArgs e)

        {

            vm.Planes=new ObservableCollection<Plane>()

            {

                new Plane(){Name = "B-1", Category = Category.Bomber, State = State.Unknown,},

                new Plane(){Name = "F-35",Category = Category.Fighter,State = State.Unknown,},

                new Plane(){Name = "B-6", Category = Category.Bomber, State = State.Unknown,},

                new Plane(){Name = "F-22",Category = Category.Fighter,State = State.Unknown,},

                new Plane(){Name = "J-20",Category = Category.Fighter,State = State.Unknown,},

            };

        }


        private void ButtonSave_OnClick(object sender, RoutedEventArgs e)

        {

            StringBuilder sb = new StringBuilder();

            foreach (var plane in vm.Planes)

            {

                sb.Append($"{plane.Category},{plane.Name},{plane.State}\r\n");

            }

            vm.Output = sb.ToString();

        }

    }

USB Microphone https://www.soft-voice.com/

Wooden Speakers  https://www.zeshuiplatform.com/

亚马逊测评 www.yisuping.cn

深圳网站建设www.sz886.com

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容