C#WPF样式触发器正在触发,但未在TextBox上设置边距

时间:2018-12-25 11:19:11

标签: c# wpf fluentvalidation

我试图在我的应用程序中实现验证,并作为示例/教程偶然发现了这一点

https://gist.github.com/holymoo/11243164

实现此功能后,我的xaml中包含以下元素。它可以工作,但是错误消息重叠,所以我寻找了一个解决方案,为什么它会重叠并且显然AdornedElementPlaceholder不会重新呈现整个UI。然后,我查看了样式触发器,并在此处找到了一些关于stackoverflow的示例,但是对我而言,运气不好的话就没有运气了。

<TextBox Text="{Binding GalaxyName, Mode=TwoWay, ValidatesOnDataErrors=True, ValidatesOnNotifyDataErrors=True, ValidatesOnExceptions=True}" 
         Grid.Column="1" x:Name="GalaxyName" Margin="0,0,10,0">
    <Validation.ErrorTemplate>
        <ControlTemplate>
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="20"></RowDefinition>
                    <RowDefinition Height="auto"></RowDefinition>
                </Grid.RowDefinitions>
                <Border Grid.Row="1" BorderBrush="Red" BorderThickness="1">
                    <AdornedElementPlaceholder x:Name="Adorner"/>
                </Border>
                <TextBlock Grid.Row="0" Foreground="Red" Text="{Binding [0].ErrorContent}"></TextBlock>
            </Grid>
        </ControlTemplate>
    </Validation.ErrorTemplate>
    <TextBox.Style>
        <Style TargetType="TextBox">
            <Style.Triggers>
                <Trigger Property="Validation.HasError" Value="True">
                    <!-- increase the top margin of the TextBox in order for the error content not to overlap the control above -->
                    <Setter Property="Margin" Value="0 20 0 0" />
                </Trigger>
            </Style.Triggers>
        </Style>
    </TextBox.Style>
</TextBox>

Validator

public class GalaxyValidator : AbstractValidator<NewGalaxyViewModel>
{
    public GalaxyValidator()
    {
        RuleFor(user => user.GalaxyName)
            .NotEmpty()
            .WithMessage("Please Specify a Name.");
    }
}

Viewmodel

public class NewGalaxyViewModel : ViewModelBase, INotifyPropertyChanged, IDataErrorInfo
{
    private readonly GalaxyValidator _galaxyValidator;
    public Galaxy Galaxy { get; set; } = new Galaxy();
    public bool DefaultEconomy { get; set; } = false;
    public bool DefaultJobs { get; set; } = false;

    private RelayCommand _saveCommand = null;
    public RelayCommand SaveCommand
    {
        get { return _saveCommand; }
        set { _saveCommand = value; }
    }

    /** wrapping each property for validation possibilities **/

    public long Seed { get { return Galaxy.Seed;  } set { Galaxy.Seed = value; } }
    public String GalaxyName { get { return Galaxy.GalaxyName; } set { Galaxy.GalaxyName = value; RaisePropertyChanged("GalaxyName"); } }
    public String GalaxyPrefix { get { return Galaxy.GalaxyPrefix; } set { Galaxy.GalaxyPrefix = value; } }
    public GalaxyOptions GalaxyOptions { get { return Galaxy.GalaxyOptions; } set { Galaxy.GalaxyOptions = value; } }
    public String Description { get { return Galaxy.Description; } set { Galaxy.Description = value; } }
    public String Author { get { return Galaxy.Author; } set { Galaxy.Author = value; } }
    public String Version { get { return Galaxy.Version; } set { Galaxy.Version = value; } }
    public String Date { get { return Galaxy.Date; } set { Galaxy.Date = value; } }
    public String Save { get { return Galaxy.Save; } set { Galaxy.Save = value; } }
    public int MinRandomBelts { get { return Galaxy.MinRandomBelts; } set { Galaxy.MinRandomBelts = value; } }
    public int MaxRandomBelts { get { return Galaxy.MaxRandomBelts; } set { Galaxy.MaxRandomBelts = value; } }

    public NewGalaxyViewModel() {
        this._saveCommand = new RelayCommand(() => OnSaveClicked());
        _galaxyValidator = new GalaxyValidator();
    }

    private void OnSaveClicked()
    {
        if (DefaultJobs)
        {
            string path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), @"DefaultJson\DefaultJobs.json");
            ObservableCollection<Job> jobs = JsonConvert.DeserializeObject<ObservableCollection<Job>>(File.ReadAllText(path));
            Galaxy.Jobs = jobs;
        }

        if (DefaultEconomy)
        {
            string path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), @"DefaultJson\DefaultProducts.json");
            ObservableCollection<Product> products = JsonConvert.DeserializeObject<ObservableCollection<Product>>(File.ReadAllText(path));
            Galaxy.Products = products;
        }

        MainData.CreateMapGalaxy(Galaxy, 20, 20, 75);
        MainViewModel vm = (App.Current.Resources["Locator"] as ViewModelLocator).Main;
        vm.Galaxy = Galaxy;
        vm.MainContainer = new MapEditorViewModel(Galaxy);
    }

    public string this[string columnName]
    {
        get
        {
            if(Galaxy != null)
            {
                var firstOrDefault = _galaxyValidator.Validate(this).Errors.FirstOrDefault(lol => lol.PropertyName == columnName);
                if (firstOrDefault != null)
                    return _galaxyValidator != null ? firstOrDefault.ErrorMessage : "";
            }
            return "";
        }
    }

    public string Error
    {
        get
        {
            if (_galaxyValidator != null)
            {
                var results = _galaxyValidator.Validate(this);
                if (results != null && results.Errors.Any())
                {
                    var errors = string.Join(Environment.NewLine, results.Errors.Select(x => x.ErrorMessage).ToArray());
                    return errors;
                }
            }
            return string.Empty;
        }
    }
}

最终结果

End Result

我使用这种技术来检查触发器是否正常工作

In WPF, how to debug triggers?

0 个答案:

没有答案