C# 更改文本框边框颜色的最佳实践?

C# 更改文本框边框颜色的最佳实践?,c#,wpf,user-interface,mvvm,C#,Wpf,User Interface,Mvvm,假设您有一个具有多个文本框的视图,如下所示 <TextBox Text="{Binding myText1, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" /> <TextBox Height="23" Text="{Binding myText1, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" Bord

假设您有一个具有多个文本框的视图,如下所示

<TextBox Text="{Binding myText1, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" />
<TextBox Height="23"  Text="{Binding myText1, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" BorderThickness="2">
   <TextBox.Style>
        <Style TargetType="TextBox">
             <Style.Triggers>
                 <DataTrigger Binding="{Binding myDirtyText1, UpdateSourceTrigger=PropertyChanged}" Value="True">
                     <Setter Property="BorderBrush" Value="Orange"/>
                 </DataTrigger>
             </Style.Triggers>
        </Style>
    </TextBox.Style>
</TextBox>
视图模型 我所看到的应该是这样的 看法

视图模型
public类MenuangebotVM:DetailVM,IContains
{
#区域私人价值观
private Menuangebot myOriginal=new Menuangebot();
private Menuangebot myValue=new Menuangebot();
#endregion//私有值
#区域属性
#区域详细信息属性
public int Id{get{return myOriginal.Id;}}
公共布尔?结果{get;private set;}
公共字符串Beschreibung{get{返回“Einrichtung”;}
[必需]
[正则表达式(@“[0-9a-zA-ZäöüßÄÜß”-'\s]{2,40}$”)
[默认值(myOriginal.Name)]//Reg(()=>NameD));
}
}
[必需]
[正则表达式(@“[0-9a-zA-ZäößÄäßß”-'\s]{2,25}$”)
[默认值(myOriginal.Anzeigetext)]//Reg(()=>AnzeigetextD));
}
}
[必需]
[默认值(myOriginal.Preis)]//Reg(()=>PreisD));
}
}    
#endregion//详细信息属性
#endregion//属性
//更多代码
}
公共类视图模型:INotifyPropertyChanged
{
私有字符串初始文本;
公共视图模型()
{
Text=“ABCD”;
initialText=文本;
DefaultBorder=true;
}
私有字符串文本;
公共字符串文本
{
获取{返回文本;}
设置{text=value;
如果(值==初始文本)
DefaultBorder=true;
其他的
DefaultBorder=false;
通知(“文本”);}
}
私人边界;
公共边界
{
获取{return defaultBorder;}
设置{defaultBorder=value;通知(“defaultBorder”);}
}
私有void Notify(字符串propertyName)
{
if(PropertyChanged!=null)
PropertyChanged(这是新的PropertyChangedEventArgs(propertyName));
}
公共事件属性更改事件处理程序属性更改;
}
公共类MyConverter:IValueConverter
{
公共对象转换(对象值、类型targetType、对象参数、System.Globalization.CultureInfo区域性)
{
如果(value!=null&&value为bool&&!(bool)value)
返回新的SolidColorBrush(颜色为橙色);
其他的
返回新的SolidColorBrush(Colors.Navy);//或默认值
}
公共对象转换回(对象值、类型targetType、对象参数、System.Globalization.CultureInfo区域性)
{
抛出新的NotImplementedException();
}
}

在这里,我在ViewModel中拥有绑定到TextBox的属性文本,并且在开始时保留了初始文本值。然后,每当我在文本属性的setter中比较用户类型并相应地设置Bool属性时,此Bool属性将指定使用转换器绑定的颜色。忽略小问题,希望您能有所了解。

您可能可以将其转换为自定义控件/UserControl,并添加IsDirtyDependencyProperty,以及IsDirtyColorDependencyProperty(或附加的依赖项属性)。这样你就可以用这个替换所有的文本框,而不必一遍又一遍地重复代码。

巧合的是,我遇到了一个与你的问题几乎相同的问题,我通过将
文本框
包装在
边框中解决了这个问题。此外,这还解决了在Windows 8机器上无法更改边框笔刷颜色的问题


因此,我建议采取这种做法。代码非常简单,只需将文本框添加到
边框
,并更改边框的
BorderBrush
属性即可。

您可以使用附加行为来实现此目的

public static class TextChangedAttachedBehavior
{
    public static bool GetChanged(DependencyObject obj)
    {
        return (bool)obj.GetValue(ChangedProperty);
    }

    public static void SetChanged(DependencyObject obj, string value)
    {
        obj.SetValue(ChangedProperty, value);
    }

    public static readonly DependencyProperty ChangedProperty =
        DependencyProperty.RegisterAttached("Changed", typeof(bool),
        typeof(TextChangedAttachedBehavior), new PropertyMetadata(false, HookupBehavior));

    private static void HookupBehavior(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var textBox = d as TextBox;
        if (textBox == null) 
            return;
        textBox.TextChanged += TextBoxOnTextChanged;
    }

    private static void TextBoxOnTextChanged(object sender, TextChangedEventArgs args)
    {
        var textBox = sender as TextBox;
        if (textBox == null)
            return;
        textBox.BorderBrush = new SolidColorBrush(Colors.Orange);
    }
}
而不是xaml

<TextBox Text="{Binding myText1, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" TextChangedAttachedBehavior.Changed = "True" />


所以你像TYY建议的那样创建了一个服装控件?@WiiMaxx-不,我的方法要简单得多。实际上,只需将文本框包装在
边框中
控件即可。不需要任何自定义控件。请给我举个例子,因为我目前看不到您的解决方案有什么改进。我目前无法访问任何代码,但是您可以在这里阅读
边框
控件及其属性:您可能会注意到属性
子项
非常适合存储您的TextBox.mhh,因此我只移动了文本属性中的问题(自重复),并没有拒绝它们。我认为可能有一个
ValidationAttribute
解决方案。你的意思是你想在文本中显示橙色边框画笔作为错误。如果实际的
Text!=startText
<Grid Margin="12">
    <Label Content="Name:" Height="28" HorizontalAlignment="Left" VerticalAlignment="Top" Width="79" />
    <TextBox Height="23" HorizontalAlignment="Left" Margin="102,2,0,0" VerticalAlignment="Top" Width="170" BorderThickness="2"
             Text="{Binding NameD, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, EditesOnDataChanges=true}">

    </TextBox>

    <Label Content="Anzeigetext:" Height="28" HorizontalAlignment="Left" Margin="0,34,0,0" VerticalAlignment="Top" Width="79" />
    <TextBox BorderThickness="2" Height="23" HorizontalAlignment="Left" Margin="102,36,0,0" VerticalAlignment="Top" Width="170" 
             Text="{Binding AnzeigetextD, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, EditesOnDataChanges=true}">
    </TextBox>

    <Label Content="Preis:" Height="28" HorizontalAlignment="Left" Margin="0,68,0,0" VerticalAlignment="Top" Width="79" />
    <TextBox BorderThickness="2" Height="23" HorizontalAlignment="Left" Margin="102,70,0,0" VerticalAlignment="Top" Width="170" 
             Text="{Binding PreisD, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, StringFormat=\{0:c\, EditesOnDataChanges=true}}">
    </TextBox>

    <Button Content="Speichern" Height="23" HorizontalAlignment="Left" Margin="102,110,0,0" VerticalAlignment="Top" Width="75" Command="{Binding SaveCommand}"/>
    <Button Content="Abbrechen" Height="23" HorizontalAlignment="Left" Margin="197,110,0,0" VerticalAlignment="Top" Width="75" Command="{Binding CancelCommand}"/>
</Grid>
public class MenuangebotVM : DetailVM, IContains
{
    #region private Values
    private Menuangebot myOriginal = new Menuangebot();
    private Menuangebot myValue = new Menuangebot();
    #endregion // private Values

    #region Properties

    #region Detail Properties
    public int Id { get { return myOriginal.Id; } }
    public bool? Result { get; private set; }
    public string Beschreibung { get { return "Einrichtung"; } }

    [Required]
    [RegularExpression(@"^[0-9a-zA-ZäöüßÄÖÜß''-'\s]{2,40}$")]
    [Default(myOriginal.Name)] //<-- added
    public string NameD
    {
        get { return myValue.Name; }
        set
        {
            myValue.Name = value;
            RaisePropertyChanged(() => Reg(() => NameD));
        }
    }

    [Required]
    [RegularExpression(@"^[0-9a-zA-ZäöüßÄÖÜß''-'\s]{2,25}$")]
    [Default(myOriginal.Anzeigetext)] //<-- added
    public string AnzeigetextD
    {
        get { return myValue.Anzeigetext; }
        set
        {
            myValue.Anzeigetext = value;
            RaisePropertyChanged(() => Reg(() => AnzeigetextD));
        }
    }

    [Required]
    [Default(myOriginal.Preis)] //<-- added
    public decimal PreisD
    {
        get { return myValue.Preis; }
        set
        {
            myValue.Preis = value;
            RaisePropertyChanged(() => Reg(() => PreisD));
        }
    }    
    #endregion //Detail Properties
    #endregion //Properties

// more code

}
public class ViewModel:INotifyPropertyChanged
    {
        private string initialText;
        public ViewModel()
        {
            Text = "ABCD";
            initialText = Text;
            DefaultBorder = true;
        }
        private string text;
        public string Text
        {
            get { return text; }
            set { text = value;
            if (value == initialText)
                DefaultBorder = true;
            else
                DefaultBorder = false;
                Notify("Text"); }
        }

        private bool defaultBorder;
        public bool DefaultBorder
        {
            get { return defaultBorder; }
            set { defaultBorder = value; Notify("DefaultBorder"); }
        }

        private void Notify(string propertyName)
        {
            if(PropertyChanged!=null)
                PropertyChanged(this,new PropertyChangedEventArgs(propertyName));
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }

public class MyConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value != null && value is bool && !(bool)value)
                return new SolidColorBrush(Colors.Orange);
            else
                return new SolidColorBrush(Colors.Navy); //Or default whatever you want

        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    <Window.Resources>
    <local:MyConverter x:Key="MyConverter"/>
</Window.Resources>
<Grid>
    <TextBox BorderThickness="4" BorderBrush="{Binding DefaultBorder, Converter={StaticResource MyConverter}}" Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
public static class TextChangedAttachedBehavior
{
    public static bool GetChanged(DependencyObject obj)
    {
        return (bool)obj.GetValue(ChangedProperty);
    }

    public static void SetChanged(DependencyObject obj, string value)
    {
        obj.SetValue(ChangedProperty, value);
    }

    public static readonly DependencyProperty ChangedProperty =
        DependencyProperty.RegisterAttached("Changed", typeof(bool),
        typeof(TextChangedAttachedBehavior), new PropertyMetadata(false, HookupBehavior));

    private static void HookupBehavior(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var textBox = d as TextBox;
        if (textBox == null) 
            return;
        textBox.TextChanged += TextBoxOnTextChanged;
    }

    private static void TextBoxOnTextChanged(object sender, TextChangedEventArgs args)
    {
        var textBox = sender as TextBox;
        if (textBox == null)
            return;
        textBox.BorderBrush = new SolidColorBrush(Colors.Orange);
    }
}
<TextBox Text="{Binding myText1, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" TextChangedAttachedBehavior.Changed = "True" />