超越数据验证样式:基于其他属性的样式

发布于 2024-09-28 05:33:10 字数 2120 浏览 5 评论 0原文

我希望这个问题没有在其他地方被问到,但我很难找到正确的搜索词来提出这个问题的任何现有答案。

我正在 C# WPF (MVVM) 中实现一个程序,其中包含许多采访式屏幕,用户可以在其中按顺序输入科学数据。我们希望让 TextboxDataGrid 根据该控件中的数据是否已由用户输入来单独更改前景色和背景色,由程序作为默认值输入,或者是用户导入的另一个文件中的模板值。最重要的是,我们希望 UI 能够响应 ViewModel 中实现的 IDataErrorInfo 的验证检查。

因此,如果 TextBox 中显示的数据是模板值,则显示为蓝色;如果是程序默认值,则显示为绿色;如果是用户输入的,则显示为黑色;如果 IDataErrorInfo 表明这是错误数据,则显示为红色。

我实现此目的的最初答案是创建一个自定义类:

class AdornerString{

private string _myString;
private bool _isTemplate;
private bool _isDefault;

public string MyString{ 
  get{
      etc.
  }
  set{
      etc.
  }
}
// accessor properties and Constructors omitted for brevity
}

然后我将所有 TextBox.Text 属性都绑定在视图中,如下所示:

<TextBox Text="{Binding Path=someAdornerString.MyString,UpdateSourceTrigger=PropertyChanged,ValidatesOnDataErrors=True}"/>

并应用带有 DataTriggers 的样式来响应 someAdornerString 的属性来创建适当的颜色。

但是,ViewModel 上的 IDataErrorInfo 不再验证 TextBox。为什么会这样,有更好的方法来解决我的问题吗?我无法在 AdornerString 类内部进行验证。

一种可能的解决方法,尽管不受欢迎:

我能想到的唯一其他解决方案是在 ViewModel 中为用户输入的每个字段设置两个属性 - 一个用于数据本身,另一个是与上面相同的自定义类减去字符串。但是,这意味着我无法概括文本框使用的样式。每个 TextBox 都必须有一个类似这样的自定义样式:

<TextBox.Style>
    <Style TargetType="{x:Type TextBox}"
           BasedOn="{StaticResource OtherStyle}">
        <Style.Triggers>
            <DataTrigger Binding="{Binding Path=**instanceCustomClass**.IsDefault}"
                         Value="True">
                <Setter Property="Foreground"
                        Value="Green" />
            </DataTrigger>
            <Trigger Property="Validation.HasError"
                     Value="true">
                <Setter Property="Foreground"
                        Value="OrangeRed" />
            </Trigger>
        </Style.Triggers>
    </Style>

因为每个 UI 字段都有一个与其关联的特定自定义类。

我真的宁愿不以这种方式实现,因为我可能有 100 多页输入屏幕,每个屏幕都有 1-12 个 TextBox,忽略混合中抛出的 DataGrid(使用并行数组)数据及其关联的自定义类)。

有什么想法吗?我读过有关自定义验证的内容,但我还不知道这在这种情况下有什么帮助。

I hope that this question has not been asked elsewhere, but I'm having difficulty finding the right search terms to bring up any already-existing answers to this problem.

I'm implementing a program in C# WPF (MVVM) with many interview-style screens where the user inputs scientific data in an orderly manner. We would like to have the Textbox's and DataGrid's change Foreground and Background colors on an individual basis based on whether the data in that control has been inputted by the user, inputted as a default value by the program, or is a template value from another file the user imported. On top of this, we would like the UI to respond to validation checks from IDataErrorInfo implemented in the ViewModel.

Thus, the data displayed in a TextBox could be blue if it is a templated value, green if a program default, black if user inputed, and red if IDataErrorInfo says it is bad data.

My initial answer for implementing this was to create a custom class:

class AdornerString{

private string _myString;
private bool _isTemplate;
private bool _isDefault;

public string MyString{ 
  get{
      etc.
  }
  set{
      etc.
  }
}
// accessor properties and Constructors omitted for brevity
}

Then I have all my TextBox.Text properties in the View bound like so:

<TextBox Text="{Binding Path=someAdornerString.MyString,UpdateSourceTrigger=PropertyChanged,ValidatesOnDataErrors=True}"/>

and apply a style with DataTriggers that responds to someAdornerString's properties to create the appropriate colors.

However, IDataErrorInfo on the ViewModel doesn't validate the TextBox anymore. Why is this so, and is there a better way to solve my problem? I can't validate inside the AdornerString class.

A possible work-around, though undesirable:

The only other solution I can think of is to have two properties in the ViewModel for each field entered by the user- one for the data itself and the other being the same custom class as above minus the string. However, this means I can't generalize the style used for the textboxes. Each TextBox would have to have a custom style something like this:

<TextBox.Style>
    <Style TargetType="{x:Type TextBox}"
           BasedOn="{StaticResource OtherStyle}">
        <Style.Triggers>
            <DataTrigger Binding="{Binding Path=**instanceCustomClass**.IsDefault}"
                         Value="True">
                <Setter Property="Foreground"
                        Value="Green" />
            </DataTrigger>
            <Trigger Property="Validation.HasError"
                     Value="true">
                <Setter Property="Foreground"
                        Value="OrangeRed" />
            </Trigger>
        </Style.Triggers>
    </Style>

since each UI field has a specific custom class associated with it.

I would seriously rather not implement this way, as I have possibly 100+ pages of input screens, with each screen having 1-12 TextBox's each, ignoring the DataGrids thrown in the mix (with parellel arrays of data and their associated custom classes).

Any ideas? I've read about custom validation, though I yet don't see how this might help in this case.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

暮年 2024-10-05 05:33:10

忽略使用 IDataErrInfo 验证,因为您似乎确实希望将其设为 4 个值之一......而“坏”数据恰好是其中之一。

您需要将这些物品放在一个公平的竞争环境中,因为您对它们的处理方式相同,只是颜色不同。将单个属性与包装 ViewModel 中模型的值和状态的对象结合使用。忽略 IDataErroInfo,然后使用转换器提供着色,然后将委托添加到 AdornerString,该委托将设置为在 ViewModel 中为其编写的验证函数。

Ignore making use of the IDataErrInfo validation all together, as it seems that the you really want to make it 1 of 4 values...and 'bad' data just happens to be one of them.

You need to keep the items on an even playing field since you are treating them the same, just differentiating colors. Use a single property with an object wrapping the value and the state of the model within the ViewModel. Ignore IDataErroInfo and then use a converter to provide the coloring and then add a delegate to the AdornerString that will be set to the validation function written in the ViewModel for it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文